<?php

declare(strict_types=1);

namespace App\Framework\Queue\MachineLearning;

use App\Framework\MachineLearning\ModelManagement\ModelRegistry;
use App\Framework\MachineLearning\ModelManagement\ModelPerformanceMonitor;
use App\Framework\MachineLearning\ModelManagement\ValueObjects\ModelMetadata;
use App\Framework\Core\ValueObjects\Version;
use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\Queue\MachineLearning\ValueObjects\JobFeatures;
use App\Framework\Queue\MachineLearning\ValueObjects\JobAnomalyResult;

/**
 * Queue Job Anomaly Detection Model Management Adapter
 *
 * Integrates JobAnomalyDetector with the ML Model Management System:
 * - Automatic model registration
 * - Real-time performance tracking
 * - Prediction monitoring
 * - Configuration management
 *
 * Usage:
 * ```php
 * $adapter = new QueueAnomalyModelAdapter($registry, $performanceMonitor, $detector);
 *
 * // Register current model version
 * $adapter->registerCurrentModel();
 *
 * // Analyze with tracking
 * $result = $adapter->analyzeWithTracking($features, $groundTruth);
 * ```
 */
final readonly class QueueAnomalyModelAdapter
{
    private const MODEL_NAME = 'queue-anomaly';
    private const CURRENT_VERSION = '1.0.0';

    public function __construct(
        private ModelRegistry $registry,
        private ModelPerformanceMonitor $performanceMonitor,
        private JobAnomalyDetector $detector
    ) {}

    /**
     * Register current queue anomaly model in registry
     */
    public function registerCurrentModel(?array $performanceMetrics = null): ModelMetadata
    {
        $version = Version::fromString(self::CURRENT_VERSION);

        // Check if already registered
        if ($this->registry->exists(self::MODEL_NAME, $version)) {
            return $this->registry->get(self::MODEL_NAME, $version);
        }

        // Create metadata
        $metadata = ModelMetadata::forQueueAnomaly(
            version: $version,
            configuration: $this->detector->getConfiguration()
        );

        // Add performance metrics if provided
        if ($performanceMetrics !== null) {
            $metadata = $metadata->withPerformanceMetrics($performanceMetrics);
        }

        // Register in registry
        $this->registry->register($metadata);

        return $metadata;
    }

    /**
     * Analyze job features with automatic performance tracking
     *
     * @param JobFeatures $features Job execution features
     * @param bool|null $groundTruth Ground truth (if known) - true if job is anomalous
     *
     * @return array Analysis result with tracking info
     */
    public function analyzeWithTracking(
        JobFeatures $features,
        ?bool $groundTruth = null
    ): array {
        // Perform ML analysis
        $analysisResult = $this->detector->detect($features);

        // Determine prediction
        $prediction = $analysisResult->isAnomalous;
        $confidence = $analysisResult->anomalyScore->value(); // Already 0.0-1.0 range

        // Track prediction in performance monitor
        $this->performanceMonitor->trackPrediction(
            modelName: self::MODEL_NAME,
            version: Version::fromString(self::CURRENT_VERSION),
            prediction: $prediction,
            actual: $groundTruth,
            confidence: $confidence,
            features: $this->extractFeatureSummary($analysisResult)
        );

        // Convert result to array format
        $resultArray = [
            'is_anomalous' => $analysisResult->isAnomalous,
            'anomaly_score' => $analysisResult->anomalyScore->value(),
            'feature_scores' => array_map(
                fn($score) => $score->value(),
                $analysisResult->featureScores
            ),
            'detected_patterns' => $analysisResult->detectedPatterns,
            'primary_indicator' => $analysisResult->primaryIndicator,
            'success' => true
        ];

        // Add tracking info
        $resultArray['tracking'] = [
            'model_name' => self::MODEL_NAME,
            'model_version' => self::CURRENT_VERSION,
            'prediction' => $prediction ? 'anomalous' : 'normal',
            'ground_truth' => $groundTruth,
            'tracked' => true,
        ];

        return $resultArray;
    }

    /**
     * Get current model performance metrics
     */
    public function getCurrentPerformanceMetrics(): array
    {
        return $this->performanceMonitor->getCurrentMetrics(
            self::MODEL_NAME,
            Version::fromString(self::CURRENT_VERSION)
        );
    }

    /**
     * Check if model performance has degraded
     */
    public function checkPerformanceDegradation(float $thresholdPercent = 0.05): array
    {
        return $this->performanceMonitor->getPerformanceDegradationInfo(
            self::MODEL_NAME,
            Version::fromString(self::CURRENT_VERSION),
            $thresholdPercent
        );
    }

    /**
     * Update model configuration in registry
     */
    public function updateConfiguration(array $newConfiguration): void
    {
        $version = Version::fromString(self::CURRENT_VERSION);
        $metadata = $this->registry->get(self::MODEL_NAME, $version);

        if ($metadata === null) {
            throw new \RuntimeException(
                'Model not registered. Call registerCurrentModel() first.'
            );
        }

        $updated = $metadata->withConfiguration($newConfiguration);
        $this->registry->update($updated);
    }

    /**
     * Deploy current model to production
     */
    public function deployToProduction(): void
    {
        $version = Version::fromString(self::CURRENT_VERSION);
        $metadata = $this->registry->get(self::MODEL_NAME, $version);

        if ($metadata === null) {
            throw new \RuntimeException(
                'Model not registered. Call registerCurrentModel() first.'
            );
        }

        $deployed = $metadata->withDeployment(
            environment: 'production',
            deployedAt: Timestamp::now()
        );

        $this->registry->update($deployed);
    }

    /**
     * Get model metadata
     */
    public function getModelMetadata(): ?ModelMetadata
    {
        return $this->registry->get(
            self::MODEL_NAME,
            Version::fromString(self::CURRENT_VERSION)
        );
    }

    /**
     * Extract feature summary for tracking
     */
    private function extractFeatureSummary(JobAnomalyResult $result): array
    {
        return [
            'feature_count' => count($result->featureScores),
            'pattern_count' => count($result->detectedPatterns),
            'primary_indicator' => $result->primaryIndicator,
            'is_anomalous' => $result->isAnomalous,
        ];
    }
}
