<?php

declare(strict_types=1);

if (! defined('ABSPATH')) {
	exit;
}

require_once CRTODAY_PLUGIN_DIR . 'includes/trait-crtoday-color-helpers.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/trait-crtoday-decimal-helpers.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/trait-crtoday-rate-helpers.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-widget-template.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-source-selection.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-source-cache.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-exchange-rates-block.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-converter-block.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-ticker-block.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-rate-card-block.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-price-badge-block.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-plugin-settings.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-review-banner.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-storage-installer.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-raw-snapshot-repository.php';
require_once CRTODAY_PLUGIN_DIR . 'includes/class-crtoday-chart-api.php';

final class CRToday_Plugin {
	public static function bootstrap(): void {
		add_action('init', [self::class, 'init']);
		add_filter(
			'plugin_action_links_' . plugin_basename(CRTODAY_PLUGIN_FILE),
			[self::class, 'add_settings_link']
		);
		add_filter(
			'plugin_row_meta',
			[self::class, 'add_row_meta_links'],
			10,
			2
		);
		add_filter('cron_schedules', [self::class, 'add_cron_schedules']);
		CRToday_Storage_Installer::maybe_install();
		CRToday_Plugin_Settings::register();
		CRToday_Review_Banner::register();
		CRToday_Chart_Api::register();

		self::ensure_cron_scheduled();
	}

	/**
	 * Add quick Settings link on plugins.php.
	 *
	 * @param array<int,string> $links Existing plugin action links.
	 * @return array<int,string>
	 */
	public static function add_settings_link(array $links): array {
		$settings_url = admin_url('admin.php?page=crtoday-plugin-settings');
		$settings_link = sprintf(
			'<a href="%s">%s</a>',
			esc_url($settings_url),
			esc_html__('Settings', 'currencyrate-today-currency-blocks')
		);

		array_unshift($links, $settings_link);

		return $links;
	}

	/**
	 * Add "Got Question?" and "Rate us" links to plugin row meta on plugins.php.
	 *
	 * @param array<int,string> $meta   Existing row meta.
	 * @param string            $file   Plugin basename.
	 * @return array<int,string>
	 */
	public static function add_row_meta_links(array $meta, string $file): array {
		if ($file !== plugin_basename(CRTODAY_PLUGIN_FILE)) {
			return $meta;
		}

		$meta[] = sprintf(
			'<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
			esc_url('https://wordpress.org/support/plugin/currencyrate-today-currency-blocks/'),
			esc_html__('Got Question?', 'currencyrate-today-currency-blocks')
		);

		$meta[] = sprintf(
			'<a href="%s" target="_blank" rel="noopener noreferrer" style="font-weight:bold">%s</a>',
			esc_url('https://wordpress.org/support/plugin/currencyrate-today-currency-blocks/reviews/#new-post'),
			esc_html__('Rate us ★★★★★', 'currencyrate-today-currency-blocks')
		);

		return $meta;
	}

	public static function init(): void {
		CRToday_Exchange_Rates_Block::register();
		CRToday_Converter_Block::register();
		CRToday_Ticker_Block::register();
		CRToday_Rate_Card_Block::register();
		CRToday_Price_Badge_Block::register();
	}

	public static function activate(): void {
		CRToday_Storage_Installer::maybe_install();

		if (get_option(CRToday_Plugin_Settings::option_name(), null) === null) {
			add_option(CRToday_Plugin_Settings::option_name(), [
				'retention'      => 2,
				'api_interval'   => 15,
				'rounding_mode'  => 'half_even',
			]);
		}

		CRToday_Plugin_Settings::invalidate_cache();
		self::schedule_cron();
	}

	public static function deactivate(): void {
		CRToday_Plugin_Settings::invalidate_cache();
		self::unschedule_cron();
	}

	/**
	 * Register custom WP-Cron intervals matching the api_interval setting.
	 *
	 * @param array<string,array{interval:int,display:string}> $schedules Existing schedules.
	 * @return array<string,array{interval:int,display:string}>
	 */
	public static function add_cron_schedules(array $schedules): array {
		$schedules['crtoday_15min'] = [
			'interval' => 15 * MINUTE_IN_SECONDS,
			'display'  => __('Every 15 minutes', 'currencyrate-today-currency-blocks'),
		];
		$schedules['crtoday_30min'] = [
			'interval' => 30 * MINUTE_IN_SECONDS,
			'display'  => __('Every 30 minutes', 'currencyrate-today-currency-blocks'),
		];
		$schedules['crtoday_60min'] = [
			'interval' => 60 * MINUTE_IN_SECONDS,
			'display'  => __('Every 60 minutes', 'currencyrate-today-currency-blocks'),
		];
		return $schedules;
	}

	/**
	 * Ensure the background fetch cron is scheduled with the correct interval.
	 * Re-schedules if the configured interval has changed.
	 */
	private static function ensure_cron_scheduled(): void {
		$hook = CRToday_Plugin_Settings::CRON_HOOK;
		$next = wp_next_scheduled($hook);

		$config   = CRToday_Plugin_Settings::get_config();
		$interval = (int) ($config['api_interval'] ?? 15);
		$schedule = self::interval_to_schedule($interval);

		if ($next !== false) {
			/* Already scheduled — check if interval matches */
			$event = wp_get_scheduled_event($hook);
			if ($event && $event->schedule === $schedule) {
				return;
			}
			/* Interval changed — reschedule */
			wp_unschedule_event($next, $hook);
		}

		wp_schedule_event(time(), $schedule, $hook);
	}

	private static function schedule_cron(): void {
		$hook = CRToday_Plugin_Settings::CRON_HOOK;
		if (wp_next_scheduled($hook) !== false) {
			return;
		}

		$config   = CRToday_Plugin_Settings::get_config();
		$interval = (int) ($config['api_interval'] ?? 15);
		wp_schedule_event(time(), self::interval_to_schedule($interval), $hook);
	}

	private static function unschedule_cron(): void {
		$hook = CRToday_Plugin_Settings::CRON_HOOK;
		$next = wp_next_scheduled($hook);
		if ($next !== false) {
			wp_unschedule_event($next, $hook);
		}
	}

	/**
	 * Map api_interval minutes → WP-Cron schedule name.
	 */
	private static function interval_to_schedule(int $minutes): string {
		$map = [15 => 'crtoday_15min', 30 => 'crtoday_30min', 60 => 'crtoday_60min'];
		return $map[$minutes] ?? 'crtoday_15min';
	}
}
