<?php
/**
 * This file is part of the Wisewand WordPress plugin.
 *
 * @package Wisewand
 * @since 1.0.0
 * @license GPL-2.0-or-later
 *
 * This program 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.
 *
 * This program 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 program. If not, see <https://www.gnu.org/licenses/>.
 */

namespace Wisewand\Automation;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Wisewand\Utils\Options;
use Wisewand\Logging\Logger;
use Wisewand\Utils\Wisewand_API_Client;
use Wisewand\Content\Content_Manager;

/**
 * Calendar CRON Facade
 *
 * Orchestrates the four-phase editorial calendar CRON pipeline:
 *
 *   Phase 1 — CRON_Article_Generator  : dispatch generation requests
 *   Phase 2 — CRON_Status_Checker     : poll Wisewand for ready articles
 *   Phase 3 — CRON_Article_Importer   : import ready articles and publish
 *   Phase 4 — CRON_Retry_Handler      : retry failed entries with backoff
 *
 * The facade owns the shared `$run_summary` array and passes it by reference
 * to each phase object before delegation so all counters accumulate in one place.
 *
 * Payload cleaning is handled by the shared API_Payload_Cleaner utility.
 *
 * @package Wisewand
 * @since 1.0.0
 * @since 2.8.2 Refactored into facade delegating to phase classes.
 */
class Calendar_CRON {

	/**
	 * Options wrapper.
	 *
	 * @var Options
	 */
	private $options;

	/**
	 * Logger instance.
	 *
	 * @var Logger
	 */
	private $logger;

	/**
	 * Calendar entry manager.
	 *
	 * @var \Wisewand\Calendar\Calendar_Entry_Manager
	 */
	private $entry_manager;

	/**
	 * Shared run summary accumulator.
	 *
	 * @var array
	 */
	private $run_summary = array();

	/**
	 * Phase 1: article generation.
	 *
	 * @var CRON_Article_Generator
	 */
	private $generator;

	/**
	 * Phase 2: status polling.
	 *
	 * @var CRON_Status_Checker
	 */
	private $status_checker;

	/**
	 * Phase 3: import and publish.
	 *
	 * @var CRON_Article_Importer
	 */
	private $importer;

	/**
	 * Phase 4: retry failed entries.
	 *
	 * @var CRON_Retry_Handler
	 */
	private $retry_handler;

	/**
	 * Constructor.
	 *
	 * Builds all phase objects with the shared infrastructure (API client,
	 * entry manager, rate limiter) so callers only need to provide the three
	 * top-level dependencies.
	 *
	 * @since 1.0.0
	 *
	 * @param Options         $options         Options wrapper.
	 * @param Logger          $logger          Logger instance.
	 * @param Content_Manager $content_manager Content manager for import phase.
	 */
	public function __construct( Options $options, Logger $logger, Content_Manager $content_manager ) {
		$this->options = $options;
		$this->logger  = $logger;

		// Resolve shared API client.
		$wisewand_api = null;
		$api_key      = Wisewand_API_Client::get_stored_api_key();
		if ( $api_key ) {
			$wisewand_api = new Wisewand_API_Client( $api_key, $logger );
		}

		// Ensure required classes are loaded.
		if ( ! class_exists( 'Wisewand\\Calendar\\Calendar_Entry_Manager' ) ) {
			require_once WISEWAND_PLUGIN_DIR . 'includes/Calendar/Calendar_Entry_Manager.php';
		}
		if ( ! class_exists( 'Wisewand\\Utils\\Wisewand_Payload_Builder' ) ) {
			require_once WISEWAND_PLUGIN_DIR . 'includes/Utils/Wisewand_Payload_Builder.php';
		}
		if ( ! class_exists( 'Wisewand\\Automation\\CRON_Article_Generator' ) ) {
			require_once WISEWAND_PLUGIN_DIR . 'includes/Automation/CRON_Article_Generator.php';
		}
		if ( ! class_exists( 'Wisewand\\Automation\\CRON_Status_Checker' ) ) {
			require_once WISEWAND_PLUGIN_DIR . 'includes/Automation/CRON_Status_Checker.php';
		}
		if ( ! class_exists( 'Wisewand\\Automation\\CRON_Article_Importer' ) ) {
			require_once WISEWAND_PLUGIN_DIR . 'includes/Automation/CRON_Article_Importer.php';
		}
		if ( ! class_exists( 'Wisewand\\Automation\\CRON_Retry_Handler' ) ) {
			require_once WISEWAND_PLUGIN_DIR . 'includes/Automation/CRON_Retry_Handler.php';
		}

		$payload_builder     = new \Wisewand\Utils\Wisewand_Payload_Builder( $options, $logger );
		$this->entry_manager = new \Wisewand\Calendar\Calendar_Entry_Manager( $options, $logger, $payload_builder );

		$rate_limiter = new \Wisewand\Utils\Rate_Limiter( $logger );

		// Build phase objects with shared dependencies.
		$this->generator = new CRON_Article_Generator(
			$options,
			$logger,
			$wisewand_api,
			$this->entry_manager,
			$rate_limiter
		);

		$this->status_checker = new CRON_Status_Checker(
			$options,
			$logger,
			$wisewand_api,
			$this->entry_manager,
			$rate_limiter,
			$this->generator
		);

		$this->importer = new CRON_Article_Importer(
			$options,
			$logger,
			$wisewand_api,
			$content_manager,
			$this->entry_manager,
			$rate_limiter,
			$this->generator
		);

		$this->retry_handler = new CRON_Retry_Handler(
			$options,
			$logger,
			$this->entry_manager,
			$rate_limiter,
			$this->generator
		);
	}

	/**
	 * Share the current run summary with all phase objects by reference.
	 *
	 * Must be called after `$this->run_summary` is (re-)initialised so that
	 * all phases write into the same array instance.
	 *
	 * @since 2.8.2
	 */
	private function share_run_summary() {
		$this->generator->set_run_summary( $this->run_summary );
		$this->status_checker->set_run_summary( $this->run_summary );
		$this->importer->set_run_summary( $this->run_summary );
		$this->retry_handler->set_run_summary( $this->run_summary );
	}

	/**
	 * Run the status-check CRON (lightweight, every 15 minutes).
	 *
	 * Executes phases 2, 3, 3.5, and 4. Phase 1 (generation) is omitted from
	 * this lightweight run — it only executes in the full daily CRON.
	 *
	 * @since 1.0.0
	 *
	 * @param bool $force_retry When true, bypasses exponential backoff for step 4.
	 * @return array|void Run summary array, or void if CRON is disabled.
	 */
	public function run_status_check_only( $force_retry = false ) {
		if ( ! $this->options->get( 'wisewand_cron_enabled', true ) ) {
			return;
		}

		$this->logger->info( '=== Status Check CRON Started (15-min) ===' );

		$start_time = microtime( true );

		$this->run_summary = array(
			'generated'      => 0,
			'status_checked' => 0,
			'imported'       => 0,
			'retried'        => 0,
			'force_retry'    => $force_retry,
		);

		$this->share_run_summary();

		// Phase 2: check generation status.
		$this->status_checker->step_2_check_generation_status();

		// Phase 3: import articles ready for today and past-due dates.
		$this->importer->step_3_import_ready_articles();

		// Phase 3.5: publish scheduled RSS articles now due.
		$this->importer->step_3_5_publish_scheduled_rss_articles();

		// Phase 4: retry failed articles respecting exponential backoff.
		$this->retry_handler->step_4_retry_failed( $force_retry );

		$elapsed                      = round( microtime( true ) - $start_time, 2 );
		$this->run_summary['elapsed'] = $elapsed;

		$this->logger->info( '=== Status Check CRON Completed ===', $this->run_summary );

		update_option( 'wisewand_cron_last_status_check', current_time( 'mysql' ) );
		update_option( 'wisewand_cron_last_status_summary', wp_json_encode( $this->run_summary ) );

		return $this->run_summary;
	}

	/**
	 * Run the full daily CRON (heavy operations, typically at 2 AM).
	 *
	 * Executes phases 1, 3, and 4. Phase 2 (status check) is omitted because
	 * the 15-minute lightweight CRON already covers it continuously.
	 *
	 * @since 1.0.0
	 *
	 * @param bool $force_retry When true, bypasses exponential backoff for step 4.
	 * @return array|void Run summary array, or void if CRON is disabled.
	 */
	public function run( $force_retry = false ) {
		if ( ! $this->options->get( 'wisewand_cron_enabled', true ) ) {
			$this->logger->info( 'Editorial calendar CRON is disabled' );
			return;
		}

		$this->logger->info( '=== Editorial Calendar CRON Started (Daily) ===' );

		$start_time = microtime( true );

		$this->run_summary = array(
			'generated'      => 0,
			'status_checked' => 0,
			'imported'       => 0,
			'retried'        => 0,
			'force_retry'    => $force_retry,
		);

		$this->share_run_summary();

		// Phase 1: generate new articles.
		$this->generator->step_1_generate_articles();

		// Phase 2 omitted from daily CRON (handled by 15-min CRON to avoid redundancy).

		// Phase 3: import and publish ready articles.
		$this->importer->step_3_import_and_publish();

		// Phase 4: retry failed articles.
		$this->retry_handler->step_4_retry_failed( $force_retry );

		$elapsed                      = round( microtime( true ) - $start_time, 2 );
		$this->run_summary['elapsed'] = $elapsed;

		$this->logger->info( '=== Editorial Calendar CRON Completed (Daily) ===', $this->run_summary );

		update_option( 'wisewand_cron_last_run', current_time( 'mysql' ) );
		update_option( 'wisewand_cron_last_summary', wp_json_encode( $this->run_summary ) );

		return $this->run_summary;
	}

	/**
	 * Return a merged summary combining the last run results with live statistics.
	 *
	 * @since 1.0.0
	 *
	 * @return array Merged summary array.
	 */
	public function get_cron_summary() {
		$stats = $this->entry_manager->get_statistics();

		return array_merge(
			$this->run_summary,
			array(
				'total_scheduled' => $stats['total_scheduled'] ?? 0,
				'not_created'     => $stats['by_wisewand_status']['not_created'] ?? 0,
				'generating'      => $stats['by_wisewand_status']['generating'] ?? 0,
				'ready'           => $stats['by_wisewand_status']['ready'] ?? 0,
				'failed'          => $stats['by_wisewand_status']['failed'] ?? 0,
				'published'       => $stats['by_wordpress_status']['published'] ?? 0,
				'upcoming_7_days' => $stats['upcoming_7_days'] ?? 0,
			)
		);
	}

}
