<?php

declare(strict_types=1);

namespace App\Framework\MachineLearning\Scheduler;

use App\Framework\Database\NPlusOneDetection\MachineLearning\NPlusOneModelAdapter;
use App\Framework\DI\Attributes\Initializer;
use App\Framework\DI\Container;
use App\Framework\MachineLearning\ModelManagement\AlertingService;
use App\Framework\MachineLearning\ModelManagement\AutoTuningEngine;
use App\Framework\MachineLearning\ModelManagement\ModelPerformanceMonitor;
use App\Framework\MachineLearning\ModelManagement\ModelRegistry;
use App\Framework\Queue\MachineLearning\QueueAnomalyModelAdapter;
use App\Framework\Scheduler\Services\SchedulerService;
use App\Framework\Waf\MachineLearning\WafBehavioralModelAdapter;
use Psr\Log\LoggerInterface;

/**
 * ML Monitoring Scheduler Initializer
 *
 * Registers the ML monitoring scheduler during framework startup and
 * schedules all periodic monitoring jobs.
 *
 * Registered Jobs:
 * - Performance monitoring (every 5 minutes)
 * - Degradation detection (every 15 minutes)
 * - Auto-tuning (every hour)
 * - Registry cleanup (daily)
 */
final readonly class MLMonitoringSchedulerInitializer
{
    public function __construct(
        private Container $container,
        private LoggerInterface $logger
    ) {}

    /**
     * Initialize and schedule ML monitoring jobs
     */
    #[Initializer]
    public function __invoke(): MLMonitoringScheduler
    {
        $this->logger->info('Initializing ML Monitoring Scheduler');

        try {
            // Get required core dependencies
            $scheduler = $this->container->get(SchedulerService::class);
            $registry = $this->container->get(ModelRegistry::class);
            $performanceMonitor = $this->container->get(ModelPerformanceMonitor::class);
            $autoTuning = $this->container->get(AutoTuningEngine::class);
            $alerting = $this->container->get(AlertingService::class);

            // Get optional ML adapters (may not all be present)
            $n1Adapter = $this->getOptionalAdapter(NPlusOneModelAdapter::class, 'N+1 Detection');
            $wafAdapter = $this->getOptionalAdapter(WafBehavioralModelAdapter::class, 'WAF Behavioral');
            $queueAdapter = $this->getOptionalAdapter(QueueAnomalyModelAdapter::class, 'Queue Anomaly');

            // Create scheduler instance
            $mlScheduler = new MLMonitoringScheduler(
                scheduler: $scheduler,
                registry: $registry,
                performanceMonitor: $performanceMonitor,
                autoTuning: $autoTuning,
                alerting: $alerting,
                logger: $this->logger,
                n1Adapter: $n1Adapter,
                wafAdapter: $wafAdapter,
                queueAdapter: $queueAdapter
            );

            // Schedule all monitoring jobs
            $mlScheduler->scheduleAll();

            $this->logger->info('ML Monitoring Scheduler initialized and jobs scheduled successfully');

            return $mlScheduler;
        } catch (\Throwable $e) {
            $this->logger->error('Failed to initialize ML Monitoring Scheduler', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            throw $e;
        }
    }

    /**
     * Get optional adapter from container (returns null if not available)
     */
    private function getOptionalAdapter(string $adapterClass, string $systemName): ?object
    {
        try {
            if ($this->container->has($adapterClass)) {
                $adapter = $this->container->get($adapterClass);
                $this->logger->debug("ML Monitoring: {$systemName} adapter loaded");
                return $adapter;
            }

            $this->logger->debug("ML Monitoring: {$systemName} adapter not available (optional)");
            return null;
        } catch (\Throwable $e) {
            $this->logger->warning("ML Monitoring: Failed to load {$systemName} adapter", [
                'error' => $e->getMessage(),
            ]);
            return null;
        }
    }
}
