<?php

namespace App\Services;

use App\Models\DnsZone;
use App\Models\DnsZoneStatistic;
use App\Models\User;
use App\Notifications\DnsAnomalyDetected;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;

class DnsAnomalyDetectionService
{
    /**
     * Threshold-uri pentru detectarea anomaliilor
     */
    protected $thresholds = [
        'query_spike' => 300, // % creștere față de media
        'servfail_rate' => 5, // % din total queries
        'nxdomain_rate' => 10, // % din total queries
        'cache_hit_drop' => 50, // % scădere cache hit ratio
        'latency_spike' => 200, // % creștere latency
    ];

    /**
     * Verifică anomalii pentru o zonă DNS
     */
    public function checkAnomalies(DnsZone $zone, ?DnsZoneStatistic $currentStat = null): array
    {
        $anomalies = [];

        if (!$currentStat) {
            $currentStat = DnsZoneStatistic::where('domain', $zone->domain)
                ->whereNull('nameserver_id')
                ->where('period_type', 'daily')
                ->orderBy('statistic_date', 'desc')
                ->first();
        }

        if (!$currentStat) {
            return $anomalies;
        }

        // Obține media din ultimele 7 zile
        $avgStats = $this->getAverageStats($zone->domain, 7);

        if (!$avgStats) {
            return $anomalies;
        }

        // 1. Verifică spike în query-uri
        if ($avgStats['avg_queries'] > 0) {
            $queryIncrease = (($currentStat->total_queries - $avgStats['avg_queries']) / $avgStats['avg_queries']) * 100;
            if ($queryIncrease > $this->thresholds['query_spike']) {
                $anomalies[] = [
                    'type' => 'query_spike',
                    'severity' => 'warning',
                    'message' => "Creștere semnificativă de trafic: {$currentStat->total_queries} queries (+{$queryIncrease}% față de medie)",
                    'current_value' => $currentStat->total_queries,
                    'average_value' => round($avgStats['avg_queries']),
                    'threshold' => $this->thresholds['query_spike'] . '%'
                ];
            }
        }

        // 2. Verifică rata de SERVFAIL
        if ($currentStat->total_queries > 0) {
            $servfailRate = ($currentStat->servfail_responses / $currentStat->total_queries) * 100;
            if ($servfailRate > $this->thresholds['servfail_rate']) {
                $anomalies[] = [
                    'type' => 'high_servfail',
                    'severity' => 'critical',
                    'message' => "Rată ridicată de SERVFAIL: {$servfailRate}% ({$currentStat->servfail_responses} erori)",
                    'current_value' => round($servfailRate, 2) . '%',
                    'threshold' => $this->thresholds['servfail_rate'] . '%'
                ];
            }
        }

        // 3. Verifică rata de NXDOMAIN
        if ($currentStat->total_queries > 0) {
            $nxdomainRate = ($currentStat->nxdomain_responses / $currentStat->total_queries) * 100;
            if ($nxdomainRate > $this->thresholds['nxdomain_rate']) {
                $anomalies[] = [
                    'type' => 'high_nxdomain',
                    'severity' => 'warning',
                    'message' => "Rată ridicată de NXDOMAIN: {$nxdomainRate}% ({$currentStat->nxdomain_responses} răspunsuri)",
                    'current_value' => round($nxdomainRate, 2) . '%',
                    'threshold' => $this->thresholds['nxdomain_rate'] . '%'
                ];
            }
        }

        // 4. Verifică scăderea cache hit ratio
        if ($avgStats['avg_cache_hit_ratio'] > 0) {
            $cacheDropPercent = (($avgStats['avg_cache_hit_ratio'] - $currentStat->cache_hit_ratio) / $avgStats['avg_cache_hit_ratio']) * 100;
            if ($cacheDropPercent > $this->thresholds['cache_hit_drop']) {
                $anomalies[] = [
                    'type' => 'cache_hit_drop',
                    'severity' => 'warning',
                    'message' => "Scădere semnificativă a cache hit ratio: {$currentStat->cache_hit_ratio}% (media: {$avgStats['avg_cache_hit_ratio']}%)",
                    'current_value' => $currentStat->cache_hit_ratio . '%',
                    'average_value' => round($avgStats['avg_cache_hit_ratio'], 2) . '%',
                    'threshold' => $this->thresholds['cache_hit_drop'] . '%'
                ];
            }
        }

        // 5. Verifică spike în latency
        if ($avgStats['avg_latency'] > 0 && $currentStat->response_time_avg) {
            $latencyIncrease = (($currentStat->response_time_avg - $avgStats['avg_latency']) / $avgStats['avg_latency']) * 100;
            if ($latencyIncrease > $this->thresholds['latency_spike']) {
                $anomalies[] = [
                    'type' => 'latency_spike',
                    'severity' => 'warning',
                    'message' => "Creștere semnificativă a timpului de răspuns: {$currentStat->response_time_avg}μs (+{$latencyIncrease}% față de medie)",
                    'current_value' => $currentStat->response_time_avg . 'μs',
                    'average_value' => round($avgStats['avg_latency']) . 'μs',
                    'threshold' => $this->thresholds['latency_spike'] . '%'
                ];
            }
        }

        // Dacă avem anomalii, log și notifică
        if (!empty($anomalies)) {
            $this->logAnomalies($zone, $anomalies);
            $this->notifyAnomalies($zone, $anomalies);
        }

        return $anomalies;
    }

    /**
     * Obține statistici medii pe ultimele N zile
     */
    protected function getAverageStats(string $domain, int $days = 7): ?array
    {
        $stats = DnsZoneStatistic::where('domain', $domain)
            ->whereNull('nameserver_id')
            ->where('period_type', 'daily')
            ->where('statistic_date', '>=', Carbon::now()->subDays($days))
            ->where('statistic_date', '<', Carbon::today()) // Exclude ziua curentă
            ->get();

        if ($stats->isEmpty()) {
            return null;
        }

        return [
            'avg_queries' => $stats->avg('total_queries'),
            'avg_cache_hits' => $stats->avg('cache_hits'),
            'avg_cache_hit_ratio' => $stats->avg('cache_hit_ratio'),
            'avg_servfail' => $stats->avg('servfail_responses'),
            'avg_nxdomain' => $stats->avg('nxdomain_responses'),
            'avg_latency' => $stats->avg('response_time_avg'),
            'days_analyzed' => $stats->count()
        ];
    }

    /**
     * Log anomaliile detectate
     */
    protected function logAnomalies(DnsZone $zone, array $anomalies): void
    {
        foreach ($anomalies as $anomaly) {
            Log::channel('dns')->warning("DNS Anomaly detected for {$zone->domain}", [
                'domain' => $zone->domain,
                'type' => $anomaly['type'],
                'severity' => $anomaly['severity'],
                'message' => $anomaly['message']
            ]);
        }
    }

    /**
     * Notifică utilizatorul despre anomalii
     */
    protected function notifyAnomalies(DnsZone $zone, array $anomalies): void
    {
        $user = $zone->user;

        if (!$user) {
            return;
        }

        // Verifică dacă utilizatorul are notificările activate
        $notificationSettings = $user->notification_settings ?? [];
        if (isset($notificationSettings['dns_anomalies']) && !$notificationSettings['dns_anomalies']) {
            return;
        }

        // Găsește anomaliile critice
        $criticalAnomalies = array_filter($anomalies, fn($a) => $a['severity'] === 'critical');

        if (!empty($criticalAnomalies)) {
            try {
                // Trimite notificare în-app
                $user->notify(new DnsAnomalyDetected($zone, $anomalies));
            } catch (\Exception $e) {
                Log::error("Failed to send anomaly notification: " . $e->getMessage());
            }
        }
    }

    /**
     * Rulează verificarea anomaliilor pentru toate zonele active
     */
    public function checkAllZones(): array
    {
        $results = [
            'zones_checked' => 0,
            'anomalies_found' => 0,
            'zones_with_anomalies' => []
        ];

        $zones = DnsZone::where('status', 'active')->get();

        foreach ($zones as $zone) {
            $results['zones_checked']++;

            $anomalies = $this->checkAnomalies($zone);

            if (!empty($anomalies)) {
                $results['anomalies_found'] += count($anomalies);
                $results['zones_with_anomalies'][] = [
                    'domain' => $zone->domain,
                    'anomalies' => $anomalies
                ];
            }
        }

        return $results;
    }

    /**
     * Setează threshold-uri personalizate
     */
    public function setThresholds(array $thresholds): void
    {
        $this->thresholds = array_merge($this->thresholds, $thresholds);
    }
}
