<?php

/**
 * Plugin initialization class.
 *
 * @package Carticy\CheckoutShield
 */
declare (strict_types = 1);
namespace Carticy\CheckoutShield;

use Carticy\CheckoutShield\Admin\DashboardWidget;
use Carticy\CheckoutShield\Admin\OrdersColumn;
use Carticy\CheckoutShield\Admin\SettingsPage;
use Carticy\CheckoutShield\Core\Container;
use Carticy\CheckoutShield\FraudPrevention\BlocklistAdminPage;
use Carticy\CheckoutShield\FraudPrevention\BlocklistChecker;
use Carticy\CheckoutShield\FraudPrevention\BlocklistService;
use Carticy\CheckoutShield\FraudPrevention\OrderBlockMetabox;
use Carticy\CheckoutShield\Frontend\FrontendHandler;
use Carticy\CheckoutShield\Interceptors\ClassicCheckoutInterceptor;
use Carticy\CheckoutShield\Interceptors\StoreApiInterceptor;
use Carticy\CheckoutShield\Services\DetectionService;
use Carticy\CheckoutShield\Services\LoggingService;
use Carticy\CheckoutShield\Services\OrderAttributionService;
use Carticy\CheckoutShield\Services\StatsService;
use Carticy\CheckoutShield\Services\WhitelistService;
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * Main plugin initialization class.
 *
 * Implements singleton pattern to ensure only one instance exists.
 */
final class Init {
    /**
     * Singleton instance.
     *
     * @var self|null
     */
    private static ?self $instance = null;

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

    /**
     * Get the singleton instance.
     *
     * @return self
     */
    public static function get_instance() : self {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Private constructor to prevent direct instantiation.
     */
    private function __construct() {
        $this->container = new Container();
        $this->register_services();
        $this->init_hooks();
    }

    /**
     * Prevent cloning.
     */
    private function __clone() {
    }

    /**
     * Prevent unserialization.
     *
     * @throws \Exception Always throws exception.
     */
    public function __wakeup() : void {
        throw new \Exception('Cannot unserialize singleton');
    }

    /**
     * Register all services with the container.
     */
    private function register_services() : void {
        // Core services - WhitelistService first (no dependencies).
        $this->container->register( WhitelistService::class, static fn(): WhitelistService => new WhitelistService() );
        // LoggingService — handles its own proxy-aware IP resolution.
        $this->container->register( LoggingService::class, static fn(): LoggingService => new LoggingService() );
        $this->container->register( DetectionService::class, fn(): DetectionService => new DetectionService($this->container->get( LoggingService::class )) );
        // Stats service (for daily detection stats tracking).
        $this->container->register( StatsService::class, static fn(): StatsService => new StatsService() );
        // Order attribution service (depends on StatsService).
        $this->container->register( OrderAttributionService::class, fn(): OrderAttributionService => new OrderAttributionService($this->container->get( StatsService::class )) );
        // Interceptors.
        $this->container->register( StoreApiInterceptor::class, fn(): StoreApiInterceptor => new StoreApiInterceptor(
            $this->container->get( DetectionService::class ),
            $this->container->get( LoggingService::class ),
            $this->container->get( WhitelistService::class ),
            $this->container->get( OrderAttributionService::class )
        ) );
        $this->container->register( ClassicCheckoutInterceptor::class, fn(): ClassicCheckoutInterceptor => new ClassicCheckoutInterceptor(
            $this->container->get( DetectionService::class ),
            $this->container->get( LoggingService::class ),
            $this->container->get( WhitelistService::class ),
            $this->container->get( OrderAttributionService::class )
        ) );
        // Frontend.
        $this->container->register( FrontendHandler::class, static fn(): FrontendHandler => new FrontendHandler() );
        // Admin.
        $this->container->register( SettingsPage::class, fn(): SettingsPage => new SettingsPage($this->container->get( WhitelistService::class )) );
        $this->container->register( DashboardWidget::class, fn(): DashboardWidget => new DashboardWidget($this->container->get( StatsService::class ), $this->container->get( LoggingService::class )) );
        $this->container->register( OrdersColumn::class, fn(): OrdersColumn => new OrdersColumn($this->container->get( OrderAttributionService::class )) );
    }

    /**
     * Initialize all hooks.
     */
    private function init_hooks() : void {
        // Initialize interceptors.
        $this->container->get( StoreApiInterceptor::class )->register();
        $this->container->get( ClassicCheckoutInterceptor::class )->register();
        // Initialize order attribution.
        $this->container->get( OrderAttributionService::class )->register();
        // Initialize frontend handler.
        $this->container->get( FrontendHandler::class )->register();
        // Initialize admin settings, dashboard widget, and orders column.
        if ( is_admin() ) {
            $this->container->get( SettingsPage::class )->register();
            $this->container->get( DashboardWidget::class )->register();
            $this->container->get( OrdersColumn::class )->register();
        }
    }

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

    /**
     * Get a service from the container.
     *
     * @template T
     * @param class-string<T> $service_class The service class name.
     * @return T
     */
    public function get_service( string $service_class ) : object {
        return $this->container->get( $service_class );
    }

    /**
     * Get the current operating mode.
     *
     * @return string One of: learning, permissive, balanced, strict
     */
    public static function get_mode() : string {
        return get_option( 'carticy_checkout_shield_mode', 'balanced' );
    }

    /**
     * Check if the plugin is enabled.
     *
     * @return bool
     */
    public static function is_enabled() : bool {
        return get_option( 'carticy_checkout_shield_enabled', 'yes' ) === 'yes';
    }

}
