<?php
/********************************************************************
 * Copyright (C) 2024 Darko Gjorgjijoski (https://darkog.com/)
 * Copyright (C) 2024 IDEOLOGIX MEDIA Dooel (https://ideologix.com/)
 *
 * This file is property of IDEOLOGIX MEDIA Dooel (https://ideologix.com)
 * This file is part of Vimeify Plugin - https://wordpress.org/plugins/vimeify/
 *
 * Vimeify - Formerly "WP Vimeo Videos" is free software: you can redistribute
 * it and/or modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 2 of the License,
 * or (at your option) any later version.
 *
 * Vimeify - Formerly "WP Vimeo Videos" is distributed in the hope that it
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this plugin. If not, see <https://www.gnu.org/licenses/>.
 *
 * Code developed by Darko Gjorgjijoski <dg@darkog.com>.
 **********************************************************************/

namespace Vimeify\Core\Backend;

use Vimeify\Core\Abstracts\BaseProvider;
use Vimeify\Core\Utilities\FileSystem;
use Vimeify\Core\Utilities\VimeoSync;

class Cron extends BaseProvider {

	/**
	 * The synchronization processor
	 * @var VimeoSync
	 */
	protected $sync;

	/**
	 * Registers specific piece of functionality
	 * @return void
	 */
	public function register() {

		$this->sync = new VimeoSync( $this->plugin );

		add_action( 'init', [ $this, 'schedule_actions' ], 9 );
	}

	/**
	 * Return possible list of cron tasks with their intervals in seconds
	 * @return array
	 */
	private function get_actions() {
		// Use longer intervals for free Vimeo accounts to conserve API rate limits
		$is_free = $this->plugin->system()->vimeo()->is_free();

		$metadata_interval = $is_free ? 60 * MINUTE_IN_SECONDS : 10 * MINUTE_IN_SECONDS;
		$status_interval   = $is_free ? 120 * MINUTE_IN_SECONDS : 20 * MINUTE_IN_SECONDS;

		return apply_filters( 'vimeify_cron_actions', array(
			'cleanup_pull_files' => HOUR_IN_SECONDS,
			'metadata_sync'      => $metadata_interval,
			'status_sync'        => $status_interval,
		), $this->plugin );
	}

	/**
	 * Registers the Action Scheduler recurring actions
	 */
	public function schedule_actions() {

		// Check if Action Scheduler is available
		if ( ! function_exists( 'as_schedule_recurring_action' ) ) {
			$this->plugin->system()->logger()->log( 'Action Scheduler is not available. Please ensure the woocommerce/action-scheduler package is installed via Composer.', 'VIMEIFY-CRON-ERROR', 'error.log' );
			return;
		}

		foreach ( $this->get_actions() as $action_key => $interval ) {
			$hook  = sprintf( 'vimeify_action_%s', $action_key );
			$group = 'vimeify';

			// Check if this action is already scheduled
			$next_scheduled = as_next_scheduled_action( $hook, array(), $group );
			if ( ! $next_scheduled ) {
				// Schedule the recurring action
				as_schedule_recurring_action( time(), $interval, $hook, array(), $group );
				$this->plugin->system()->logger()->log( sprintf( 'Scheduled action: %s with interval %d seconds', $hook, $interval ), 'VIMEIFY-CRON', 'cron.log' );
			} else {
				// Check if the interval has changed (e.g., user upgraded from free to paid)
				$current_interval = $this->get_scheduled_interval( $hook, $group );
				if ( $current_interval && $current_interval !== $interval ) {
					// Unschedule existing actions and reschedule with new interval
					as_unschedule_all_actions( $hook, array(), $group );
					as_schedule_recurring_action( time(), $interval, $hook, array(), $group );
					$this->plugin->system()->logger()->log( sprintf( 'Rescheduled action: %s - interval changed from %d to %d seconds', $hook, $current_interval, $interval ), 'VIMEIFY-CRON', 'cron.log' );
				}
			}

			// Hook the action to the method
			if ( method_exists( $this, 'do_' . $action_key ) ) {
				add_action( $hook, array( $this, 'do_' . $action_key ) );
			}
		}
	}

	/**
	 * Get the recurrence interval of a scheduled action
	 *
	 * @param string $hook  The action hook
	 * @param string $group The action group
	 *
	 * @return int|false The interval in seconds, or false if not found
	 */
	private function get_scheduled_interval( $hook, $group ) {
		$actions = as_get_scheduled_actions( array(
			'hook'   => $hook,
			'group'  => $group,
			'status' => \ActionScheduler_Store::STATUS_PENDING,
		), 'objects' );

		if ( ! empty( $actions ) ) {
			$action   = reset( $actions );
			$schedule = $action->get_schedule();
			if ( $schedule instanceof \ActionScheduler_IntervalSchedule ) {
				return $schedule->get_recurrence();
			}
		}

		return false;
	}

	/**
	 * Clean up pull files
	 * @return void
	 */
	public function do_cleanup_pull_files() {

		$logtag = 'VIMEIFY-FILE-CLEANUP';

		$this->plugin->system()->logger()->log( 'Starting the temporary files clean up process.', $logtag, 'cron.log' );

		/**
		 * How many minutes needs to pass in order the temporary uploads used for Vimeo Pull uploading method to be removed.
		 * Warning: please make sure you leave at least 30 minutes for Vimeo to process the file. Setting this value to low may cause missing uploads.
		 */
		$removal_delay_minutes = apply_filters( 'vimeify_upload_pull_removal_delay', 180 );
		if ( $removal_delay_minutes < 20 ) { // Protection for just in case.
			$removal_delay_minutes = 100;
		}

		$time_now  = time();
		$tmp_files = $this->plugin->system()->settings()->get_temporary_files();
		if ( count( $tmp_files ) > 0 ) {
			foreach ( $tmp_files as $path => $time_age ) {
				$diff_minutes = round( abs( $time_now - $time_age ) / 60, 2 );
				$file_exists  = FileSystem::exists( $path );
				if ( $file_exists && $diff_minutes >= $removal_delay_minutes ) {
					if ( FileSystem::delete( $path ) ) {
						$this->plugin->system()->settings()->remove_from_temporary_files( $path );
						$this->plugin->system()->logger()->log( sprintf( 'Deleted temporary video file %s after %s minutes', $path, $diff_minutes ), $logtag, 'cron.log' );
					} else {
						$this->plugin->system()->logger()->log( sprintf( 'Unable to remove temporary video file %s.', $path ), $logtag, 'cron.log' );
					}
				} elseif ( ! $file_exists ) {
					$this->plugin->system()->settings()->remove_from_temporary_files( $path );
					$this->plugin->system()->logger()->log( sprintf( 'Temporary video file %s not found in the file system', $path ), $logtag, 'cron.log' );
				}
			}
		} else {
			$this->plugin->system()->logger()->log( 'No temporary files found for clean up.', $logtag, 'cron.log' );
		}
	}

	/**
	 * Sync all the videos in the library with Vimeo.com
	 * @return void
	 */
	public function do_metadata_sync() {
		$logtag = 'VIMEIFY-METADATA-SYNC';
		$this->plugin->system()->logger()->log( 'Starting metadata sync via cron.', $logtag, 'cron.log' );
		$this->sync->sync_metadata();
		$this->plugin->system()->logger()->log( 'Finished metadata sync via cron.', $logtag, 'cron.log' );
	}

	/**
	 * Sync all the videos in the library with Vimeo.com
	 * @return void
	 */
	public function do_status_sync() {
		$logtag = 'VIMEIFY-STATUS-SYNC';
		$this->plugin->system()->logger()->log( 'Starting status sync via cron.', $logtag, 'cron.log' );
		$this->sync->sync_status();
		$this->plugin->system()->logger()->log( 'Finished status sync via cron.', $logtag, 'cron.log' );
	}
}