<?php

declare(strict_types=1);

namespace App\Framework\Performance\Analysis;

use App\Framework\Performance\ValueObjects\PerformanceSnapshot;

/**
 * Result of trend analysis for performance snapshots
 *
 * Contains comprehensive trend analysis results including
 * individual metric trends, predictions, recommendations,
 * and anomaly detection results.
 */
final readonly class TrendAnalysis
{
    public function __construct(
        public array $snapshots,
        public array $metricTrends,
        public string $overallTrend,
        public array $predictions,
        public array $recommendations,
        public array $anomalies,
        public \DateTimeImmutable $analysisTimestamp,
        public float $confidence
    ) {
    }

    /**
     * Create analysis for insufficient data
     */
    public static function insufficient(array $snapshots): self
    {
        return new self(
            snapshots: $snapshots,
            metricTrends: [],
            overallTrend: 'insufficient_data',
            predictions: [],
            recommendations: ['Collect more performance data for trend analysis'],
            anomalies: [],
            analysisTimestamp: new \DateTimeImmutable(),
            confidence: 0.0
        );
    }

    /**
     * Check if trend analysis has valid trends
     */
    public function hasValidTrend(): bool
    {
        return $this->overallTrend !== 'insufficient_data' && ! empty($this->metricTrends);
    }

    /**
     * Check if performance is improving
     */
    public function isImproving(): bool
    {
        return $this->overallTrend === 'improving';
    }

    /**
     * Check if performance is degrading
     */
    public function isDegrading(): bool
    {
        return $this->overallTrend === 'degrading';
    }

    /**
     * Check if performance is stable
     */
    public function isStable(): bool
    {
        return $this->overallTrend === 'stable';
    }

    /**
     * Get trends by direction
     */
    public function getTrendsByDirection(string $direction): array
    {
        return array_filter(
            $this->metricTrends,
            fn (array $trend) => $trend['direction'] === $direction
        );
    }

    /**
     * Get metrics with concerning predictions
     */
    public function getConcerningPredictions(): array
    {
        return array_filter(
            $this->predictions,
            fn (array $prediction) => isset($prediction['alert'])
        );
    }

    /**
     * Get anomalies by severity
     */
    public function getAnomaliesBySeverity(string $severity): array
    {
        return array_filter(
            $this->anomalies,
            fn (array $anomaly) => $anomaly['severity'] === $severity
        );
    }

    /**
     * Get high severity anomalies
     */
    public function getHighSeverityAnomalies(): array
    {
        return $this->getAnomaliesBySeverity('high');
    }

    /**
     * Get recommendations by priority
     */
    public function getPriorityRecommendations(): array
    {
        // High priority recommendations for degrading trends
        if ($this->isDegrading()) {
            return array_merge(
                ['URGENT: Performance is degrading - immediate investigation required'],
                $this->recommendations
            );
        }

        // Medium priority for concerning predictions
        if (! empty($this->getConcerningPredictions())) {
            return array_merge(
                ['WARNING: Concerning performance predictions detected'],
                $this->recommendations
            );
        }

        return $this->recommendations;
    }

    /**
     * Get trend strength for a metric
     */
    public function getTrendStrength(string $metric): float
    {
        return $this->metricTrends[$metric]['strength'] ?? 0.0;
    }

    /**
     * Get trend direction for a metric
     */
    public function getTrendDirection(string $metric): string
    {
        return $this->metricTrends[$metric]['direction'] ?? 'unknown';
    }

    /**
     * Get prediction for a metric
     */
    public function getPrediction(string $metric): ?array
    {
        return $this->predictions[$metric] ?? null;
    }

    /**
     * Check if there are any critical issues
     */
    public function hasCriticalIssues(): bool
    {
        return $this->isDegrading()
            || ! empty($this->getHighSeverityAnomalies())
            || ! empty($this->getConcerningPredictions());
    }

    /**
     * Get performance health rating
     */
    public function getHealthRating(): string
    {
        if ($this->confidence < 0.3) {
            return 'insufficient_data';
        }

        if ($this->hasCriticalIssues()) {
            return 'critical';
        }

        if ($this->isDegrading()) {
            return 'poor';
        }

        if ($this->isImproving()) {
            return 'excellent';
        }

        return 'good';
    }

    /**
     * Get time period covered by analysis
     */
    public function getTimePeriod(): array
    {
        if (empty($this->snapshots)) {
            return ['start' => null, 'end' => null, 'duration' => 0];
        }

        $timestamps = array_map(
            fn (PerformanceSnapshot $snapshot) => $snapshot->startTime->toFloat(),
            $this->snapshots
        );

        $start = new \DateTimeImmutable('@' . (int) min($timestamps));
        $end = new \DateTimeImmutable('@' . (int) max($timestamps));
        $duration = $end->getTimestamp() - $start->getTimestamp();

        return [
            'start' => $start,
            'end' => $end,
            'duration' => $duration,
        ];
    }

    /**
     * Get summary of trend analysis
     */
    public function getSummary(): string
    {
        if (! $this->hasValidTrend()) {
            return 'Insufficient data for trend analysis';
        }

        $period = $this->getTimePeriod();
        $durationHours = round($period['duration'] / 3600, 1);
        $sampleCount = count($this->snapshots);

        $summary = "Analyzed {$sampleCount} performance samples over {$durationHours} hours. ";

        $summary .= match ($this->overallTrend) {
            'improving' => 'Performance trends are positive with measurable improvements.',
            'degrading' => 'Performance is degrading and requires immediate attention.',
            'stable' => 'Performance is stable with no significant changes.',
            default => 'Mixed performance trends detected.'
        };

        if (! empty($this->anomalies)) {
            $anomalyCount = count($this->anomalies);
            $summary .= " {$anomalyCount} performance anomalies detected.";
        }

        if (! empty($this->getConcerningPredictions())) {
            $concernCount = count($this->getConcerningPredictions());
            $summary .= " {$concernCount} concerning predictions require attention.";
        }

        return $summary;
    }

    /**
     * Convert to array for serialization
     */
    public function toArray(): array
    {
        $period = $this->getTimePeriod();

        return [
            'analysis_timestamp' => $this->analysisTimestamp->format('Y-m-d H:i:s'),
            'sample_count' => count($this->snapshots),
            'time_period' => [
                'start' => $period['start']?->format('Y-m-d H:i:s'),
                'end' => $period['end']?->format('Y-m-d H:i:s'),
                'duration_hours' => round($period['duration'] / 3600, 1),
            ],
            'overall_trend' => $this->overallTrend,
            'confidence' => $this->confidence,
            'health_rating' => $this->getHealthRating(),
            'has_valid_trend' => $this->hasValidTrend(),
            'has_critical_issues' => $this->hasCriticalIssues(),
            'summary' => $this->getSummary(),
            'metric_trends' => $this->metricTrends,
            'predictions' => $this->predictions,
            'concerning_predictions' => $this->getConcerningPredictions(),
            'recommendations' => $this->recommendations,
            'priority_recommendations' => $this->getPriorityRecommendations(),
            'anomalies' => $this->anomalies,
            'high_severity_anomalies' => $this->getHighSeverityAnomalies(),
            'trend_directions' => [
                'improving' => count($this->getTrendsByDirection('increasing')),
                'degrading' => count($this->getTrendsByDirection('decreasing')),
                'stable' => count($this->getTrendsByDirection('stable')),
            ],
        ];
    }

    /**
     * Create detailed report
     */
    public function createReport(): string
    {
        $report = "Performance Trend Analysis Report\n";
        $report .= str_repeat('=', 40) . "\n\n";

        $report .= "Analysis Date: " . $this->analysisTimestamp->format('Y-m-d H:i:s') . "\n";
        $report .= "Confidence Level: " . round($this->confidence * 100, 1) . "%\n\n";

        // Summary
        $report .= "Summary:\n";
        $report .= $this->getSummary() . "\n\n";

        // Overall Trend
        $report .= "Overall Performance Trend: " . strtoupper($this->overallTrend) . "\n";
        $report .= "Health Rating: " . strtoupper($this->getHealthRating()) . "\n\n";

        // Metric Trends
        if (! empty($this->metricTrends)) {
            $report .= "Metric Trends:\n";
            foreach ($this->metricTrends as $metric => $trend) {
                $direction = strtoupper($trend['direction']);
                $strength = round($trend['strength'] * 100, 1);
                $report .= "  - {$metric}: {$direction} (strength: {$strength}%)\n";
            }
            $report .= "\n";
        }

        // Predictions
        if (! empty($this->predictions)) {
            $report .= "Predictions:\n";
            foreach ($this->predictions as $metric => $prediction) {
                $value = round($prediction['predicted_value'], 2);
                $confidence = round($prediction['confidence'] * 100, 1);
                $report .= "  - {$metric}: {$value} (confidence: {$confidence}%)\n";

                if (isset($prediction['alert'])) {
                    $report .= "    WARNING: " . $prediction['alert'] . "\n";
                }
            }
            $report .= "\n";
        }

        // Recommendations
        if (! empty($this->recommendations)) {
            $report .= "Recommendations:\n";
            foreach ($this->getPriorityRecommendations() as $i => $recommendation) {
                $report .= "  " . ($i + 1) . ". {$recommendation}\n";
            }
            $report .= "\n";
        }

        // Anomalies
        if (! empty($this->anomalies)) {
            $report .= "Anomalies Detected:\n";
            foreach ($this->anomalies as $anomaly) {
                $severity = strtoupper($anomaly['severity']);
                $metric = $anomaly['metric'];
                $timestamp = date('Y-m-d H:i:s', (int) $anomaly['timestamp']);
                $report .= "  - [{$severity}] {$metric} at {$timestamp}\n";
            }
        }

        return $report;
    }
}
