<?php
/**
 * Plugin bootstrap kernel.
 *
 * @package MonitorCat
 */

declare(strict_types=1);

namespace MonitorCat;

defined( 'ABSPATH' ) || exit;

use MonitorCat\Admin\AdminManager;
use MonitorCat\Admin\AssetManager;
use MonitorCat\Admin\DashboardPage;
use MonitorCat\Admin\PageRenderer;
use MonitorCat\Module\ModuleRegistry;
use MonitorCat\Rest\RestManager;

/**
 * Singleton kernel that bootstraps the entire plugin.
 */
final class Kernel {

	/**
	 * Singleton instance.
	 *
	 * @var self|null
	 */
	private static ?self $instance = null;

	/**
	 * DI container.
	 *
	 * @var Container
	 */
	private Container $container;

	/**
	 * Whether the kernel has been booted.
	 *
	 * @var bool
	 */
	private bool $booted = false;

	/**
	 * Private constructor — use boot() to initialize.
	 */
	private function __construct() {}

	/**
	 * Boot the plugin. Called on the init hook.
	 */
	public static function boot(): void {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		self::$instance->initialize();
	}

	/**
	 * Initialize the kernel — register services, admin, and REST.
	 */
	private function initialize(): void {
		if ( $this->booted ) {
			return;
		}
		$this->booted = true;

		$this->container = new Container();
		$this->register_services();

		// Admin context only.
		if ( is_admin() ) {
			$this->container->get( AdminManager::class )->register();
		}

		// Register REST API endpoints.
		add_action(
			'rest_api_init',
			function (): void {
				$this->container->get( RestManager::class )->register();
			}
		);

		// Boot all modules.
		$this->container->get( ModuleRegistry::class )->boot_all();

		// Add "Settings" link on the Plugins page.
		add_filter(
			'plugin_action_links_' . MONITORCAT_BASENAME,
			function ( array $links ): array {
				$settings_link = sprintf(
					'<a href="%s">%s</a>',
					esc_url( admin_url( 'admin.php?page=monitor-cat' ) ),
					esc_html__( 'Dashboard', 'monitor-cat' )
				);
				array_unshift( $links, $settings_link );
				return $links;
			}
		);
	}

	/**
	 * Register all services in the DI container.
	 */
	private function register_services(): void {
		$this->container->singleton(
			Settings::class,
			static function (): Settings {
				return new Settings();
			}
		);

		$this->container->singleton(
			AssetManager::class,
			static function (): AssetManager {
				return new AssetManager();
			}
		);

		$this->container->singleton(
			PageRenderer::class,
			static function (): PageRenderer {
				return new PageRenderer();
			}
		);

		$this->container->singleton(
			ModuleRegistry::class,
			function (): ModuleRegistry {
				return new ModuleRegistry( $this->container );
			}
		);

		$this->container->singleton(
			DashboardPage::class,
			function (): DashboardPage {
				return new DashboardPage(
					$this->container->get( PageRenderer::class ),
					$this->container->get( ModuleRegistry::class )
				);
			}
		);

		$this->container->singleton(
			AdminManager::class,
			function (): AdminManager {
				return new AdminManager(
					$this->container->get( Settings::class ),
					$this->container->get( AssetManager::class ),
					$this->container->get( DashboardPage::class )
				);
			}
		);

		$this->container->singleton(
			RestManager::class,
			function (): RestManager {
				return new RestManager( $this->container->get( ModuleRegistry::class ) );
			}
		);
	}

	/**
	 * Plugin activation hook.
	 */
	public static function activate(): void {
		$settings = new Settings();
		$settings->install_defaults();
		flush_rewrite_rules();
	}

	/**
	 * Plugin deactivation hook.
	 */
	public static function deactivate(): void {
		global $wpdb;

		// Clear scheduled cron events.
		wp_clear_scheduled_hook( 'monitorcat_db_auto_cleanup' );

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->query(
			"DELETE FROM {$wpdb->options}
			WHERE option_name LIKE '_transient_monitorcat_%'
			OR option_name LIKE '_transient_timeout_monitorcat_%'"
		);

		flush_rewrite_rules();
	}

	/**
	 * Get the singleton instance.
	 *
	 * @return self|null
	 */
	public static function instance(): ?self {
		return self::$instance;
	}

	/**
	 * Get the DI container.
	 *
	 * @return Container
	 */
	public function container(): Container {
		return $this->container;
	}
}
