<?php

namespace Yoast\WP\SEO\MyYoast_Client\User_Interface;

use Exception;
use Yoast\WP\SEO\Conditionals\MyYoast_Connection_Conditional;
use Yoast\WP\SEO\Integrations\Integration_Interface;
use Yoast\WP\SEO\MyYoast_Client\Application\Ports\Client_Registration_Interface;
use YoastSEO_Vendor\Psr\Log\LoggerAwareInterface;
use YoastSEO_Vendor\Psr\Log\LoggerAwareTrait;
use YoastSEO_Vendor\Psr\Log\NullLogger;

/**
 * Registers wp-cron for registration key rotation.
 */
class MyYoast_Client_Integration implements Integration_Interface, LoggerAwareInterface {
	use LoggerAwareTrait;

	private const CRON_HOOK                 = 'wpseo_myyoast_key_rotation';
	private const ROTATION_INTERVAL         = 'wpseo_myyoast_90days';
	private const ROTATION_INTERVAL_IN_DAYS = 90;

	/**
	 * The registration manager.
	 *
	 * @var Client_Registration_Interface
	 */
	private $client_registration;

	/**
	 * MyYoast_Client_Integration constructor.
	 *
	 * @param Client_Registration_Interface $client_registration The registration manager.
	 */
	public function __construct( Client_Registration_Interface $client_registration ) {
		$this->client_registration = $client_registration;
		$this->logger              = new NullLogger();
	}

	/**
	 * Returns the conditionals based on which this integration should be loaded.
	 *
	 * @return array<string> The array of conditionals.
	 */
	public static function get_conditionals() {
		return [ MyYoast_Connection_Conditional::class ];
	}

	/**
	 * Registers hooks.
	 *
	 * @return void
	 */
	public function register_hooks() {
		\add_action( 'admin_init', [ $this, 'schedule_key_rotation' ] );
		\add_action( self::CRON_HOOK, [ $this, 'handle_key_rotation' ] );
		\add_action( 'wpseo_deactivate', [ $this, 'unschedule_key_rotation' ] );
		// phpcs:ignore WordPress.WP.CronInterval -- The sniff doesn't understand the self::ROTATION_INTERVAL_IN_DAYS reference.
		\add_filter( 'cron_schedules', [ $this, 'add_cron_schedule' ] );
	}

	/**
	 * Adds a 90-day cron schedule.
	 *
	 * @param array<string, array<string, string|int>> $schedules Existing cron schedules.
	 *
	 * @return array<string, array<string, string|int>> Modified schedules.
	 */
	public function add_cron_schedule( $schedules ) {
		if ( ! \is_array( $schedules ) ) {
			$schedules = [];
		}

		$schedules[ self::ROTATION_INTERVAL ] = [
			'interval' => ( self::ROTATION_INTERVAL_IN_DAYS * \DAY_IN_SECONDS ),
			'display'  => \esc_html__( 'Every 90 days', 'wordpress-seo' ),
		];

		return $schedules;
	}

	/**
	 * Schedules the key rotation cron job if not already scheduled.
	 *
	 * @return void
	 */
	public function schedule_key_rotation(): void {
		if ( ! \wp_next_scheduled( self::CRON_HOOK ) ) {
			\wp_schedule_event( ( \time() + ( self::ROTATION_INTERVAL_IN_DAYS * \DAY_IN_SECONDS ) ), self::ROTATION_INTERVAL, self::CRON_HOOK );
		}
	}

	/**
	 * Clears all scheduled key rotation events.
	 *
	 * @return void
	 */
	public function unschedule_key_rotation(): void {
		\wp_clear_scheduled_hook( self::CRON_HOOK );
	}

	/**
	 * Handles the key rotation cron event.
	 *
	 * @return void
	 */
	public function handle_key_rotation(): void {
		try {
			$this->client_registration->rotate_registration_keys();
		}
		catch ( Exception $e ) {
			// Best-effort — log but don't crash cron.
			$this->logger->warning( 'Yoast MyYoast key rotation failed: {error}', [ 'error' => $e->getMessage() ] );
		}
	}
}
