<?php

namespace App\Classes;

class Weather
{

    public static function GetWeatherCondition(int $code): array
    {
        return match(true) {
            $code == 0 => ['condition' => 'sunny', 'type' => 'sun', 'text' => 'آفتابی'],
            $code >= 1 && $code <= 3 => ['condition' => 'cloudy', 'type' => 'cloud', 'text' => 'ابری'],
            $code >= 45 && $code <= 48 => ['condition' => 'foggy', 'type' => 'cloud', 'text' => 'مه‌آلود'],
            $code >= 51 && $code <= 67 => ['condition' => 'rainy', 'type' => 'cloud-rain', 'text' => 'بارانی'],
            $code >= 71 && $code <= 77 => ['condition' => 'snowy', 'type' => 'cloud-snow', 'text' => 'برفی'],
            $code >= 80 && $code <= 82 => ['condition' => 'rainy', 'type' => 'cloud-rain', 'text' => 'رگبار باران'],
            $code >= 85 && $code <= 86 => ['condition' => 'snowy', 'type' => 'cloud-snow', 'text' => 'رگبار برف'],
            $code >= 95 && $code <= 99 => ['condition' => 'stormy', 'type' => 'cloud-lightning', 'text' => 'رعد و برق'],
            default => ['condition' => 'unknown', 'type' => 'cloud', 'text' => 'نامشخص']
        };
    }

    public static function GenerateDescription(array $current, array $hourly = []): string
    {
        $currentCondition = self::GetWeatherCondition($current['weather_code']);
        $temp = round($current['temperature_2m'] ?? 0);
        $windSpeed = $current['wind_speed_10m'] ?? 0;
        $humidity = $current['relative_humidity_2m'] ?? 0;

        $baseText = "در حال حاضر هوا {$currentCondition['text']} با دمای {$temp} درجه و رطوبت {$humidity}٪ است.";

        if ($windSpeed > 30) {
            $baseText .= ' وزش باد نسبتاً شدید نیز در جریان است.';
        } elseif ($windSpeed > 15) {
            $baseText .= ' نسیم ملایمی می‌وزد.';
        }

        if (empty($hourly) || empty($hourly['time']) || empty($hourly['weather_code'])) {
            return $baseText;
        }

        $currentTimestamp = strtotime($current['time']);
        $futureConditions = [];
        $futureTemps = [];
        $foundCurrent = false;
        $hoursLookahead = 0;

        foreach ($hourly['time'] as $index => $time) {
            $timeTs = strtotime($time);
            if ($timeTs >= $currentTimestamp) {
                $foundCurrent = true;
            }

            if ($foundCurrent && $hoursLookahead < 12) {
                $futureConditions[] = self::GetWeatherCondition($hourly['weather_code'][$index])['condition'];
                $futureTemps[] = $hourly['temperature_2m'][$index];
                $hoursLookahead++;
            }
        }

        $uniqueFutureConditions = array_diff($futureConditions, [$currentCondition['condition']]);
        $futureText = '';

        if (in_array('stormy', $uniqueFutureConditions)) {
            $futureText = 'در ساعات آینده احتمال وقوع رعد و برق و طوفان وجود دارد، ترجیحاً در فضای بسته بمانید.';
        } elseif (in_array('snowy', $uniqueFutureConditions)) {
            $futureText = 'برای ساعات آینده بارش برف پیش‌بینی می‌شود و احتمال لغزندگی معابر وجود دارد.';
        } elseif (in_array('rainy', $uniqueFutureConditions)) {
            $futureText = 'در ساعات آینده انتظار بارش باران می‌رود، همراه داشتن چتر توصیه می‌شود.';
        } elseif (in_array('foggy', $uniqueFutureConditions)) {
            $futureText = 'هوا در ساعات آینده مه‌آلود خواهد شد و دید افقی کاهش می‌یابد.';
        } elseif (in_array('cloudy', $uniqueFutureConditions) && $currentCondition['condition'] === 'sunny') {
            $futureText = 'آسمان در ساعات آینده به تدریج ابری خواهد شد.';
        } elseif (in_array('sunny', $uniqueFutureConditions) && in_array($currentCondition['condition'], ['cloudy', 'rainy', 'snowy', 'foggy'])) {
            $futureText = 'در ساعات آینده آسمان صاف و آفتابی خواهد شد.';
        } else {
            $futureText = 'انتظار می‌رود این شرایط جوی در ساعات آینده نیز پایداری خود را حفظ کند.';
        }

        $tempTrendText = '';
        if (!empty($futureTemps)) {
            $maxFutureTemp = max($futureTemps);
            $minFutureTemp = min($futureTemps);
            
            if ($maxFutureTemp - $temp >= 3) {
                 $tempTrendText = ' همچنین هوا رو به گرمی خواهد رفت.';
            } elseif ($temp - $minFutureTemp >= 3) {
                 $tempTrendText = ' همچنین شاهد کاهش محسوس دما خواهیم بود.';
            }
        }

        return $baseText . ' ' . $futureText . $tempTrendText;
    }

    public static function GetUVIndexText(float $uvIndex): string
    {
        $uv = round($uvIndex);
        return match(true) {
            $uv <= 2 => $uv . ' (پایین)',
            $uv <= 5 => $uv . ' (متوسط)',
            $uv <= 7 => $uv . ' (بالا)',
            $uv <= 10 => $uv . ' (خیلی بالا)',
            default => $uv . ' (خطرناک)',
        };
    }

    public static function GetPersianDayName(int $dayOfWeek): string
    {
        $days = ['یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنج‌شنبه', 'جمعه', 'شنبه'];
        return $days[$dayOfWeek] ?? 'نامشخص';
    }

    public static function ToPersianDate(int $timestamp): string
    {
        $gregorianDate = getdate($timestamp);
        $jalali = self::GregorianToJalali($gregorianDate['year'], $gregorianDate['mon'], $gregorianDate['mday']);
        
        $monthNames = [
            1 => 'فروردین',
            2 => 'اردیبهشت',
            3 => 'خرداد',
            4 => 'تیر',
            5 => 'مرداد',
            6 => 'شهریور',
            7 => 'مهر',
            8 => 'آبان',
            9 => 'آذر',
            10 => 'دی',
            11 => 'بهمن',
            12 => 'اسفند'
        ];
        
        $day = $jalali[2];
        $monthName = $monthNames[$jalali[1]];
        
        return "{$day} {$monthName}";
    }

    public static function GregorianToJalali(int $gy, int $gm, int $gd): array
    {
        $g_d_m = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
        
        if ($gy > 1600) {
            $jy = 979;
            $gy -= 1600;
        } else {
            $jy = 0;
            $gy -= 621;
        }
        
        $gy2 = ($gm > 2) ? ($gy + 1) : $gy;
        $days = (365 * $gy) + (int)(($gy2 + 3) / 4) - (int)(($gy2 + 99) / 100) + (int)(($gy2 + 399) / 400) - 80 + $gd + $g_d_m[$gm - 1];
        $jy += 33 * (int)($days / 12053);
        $days %= 12053;
        $jy += 4 * (int)($days / 1461);
        $days %= 1461;
        
        if ($days > 365) {
            $jy += (int)(($days - 1) / 365);
            $days = ($days - 1) % 365;
        }
        
        if ($days < 186) {
            $jm = 1 + (int)($days / 31);
            $jd = 1 + ($days % 31);
        } else {
            $jm = 7 + (int)(($days - 186) / 30);
            $jd = 1 + (($days - 186) % 30);
        }
        
        return [$jy, $jm, $jd];
    }

    public static function ProcessWeatherData(array $rawData): array
    {
        $current = $rawData['current'];
        $hourly = $rawData['hourly'];
        $daily = $rawData['daily'];
        
        $currentWeather = self::GetWeatherCondition($current['weather_code']);
        $currentTimestamp = strtotime($current['time']);
        
        $processedCurrent = [
            'day' => self::GetPersianDayName(date('w', $currentTimestamp)),
            'date' => self::ToPersianDate($currentTimestamp),
            'temp' => round($current['temperature_2m']),
            'condition' => $currentWeather['condition'],
            'type' => $currentWeather['type'],
            'typeText' => $currentWeather['text'],
            'description' => self::GenerateDescription($current, $hourly),
            'wind' => round($current['wind_speed_10m']),
            'humidity' => $current['relative_humidity_2m'],
            'visibility' => round(($current['visibility'] ?? 10000) / 1000),
            'uvIndex' => self::GetUVIndexText($hourly['uv_index'][0] ?? 0),
        ];
        
        $currentHourIndex = 0;
        $currentDateString = date('Y-m-d', $currentTimestamp);
        
        foreach ($hourly['time'] as $index => $time) {
            if (strtotime($time) >= $currentTimestamp) {
                $currentHourIndex = $index;
                break;
            }
        }

        $minFutureHours = 10;
        
        $processedHourly = [];
        foreach ($hourly['time'] as $i => $timeStr) {
            $hourTimestamp = strtotime($timeStr);
            $isToday = (date('Y-m-d', $hourTimestamp) === $currentDateString);
            
            $isWithinRequiredFutureHours = ($i >= $currentHourIndex && $i <= $currentHourIndex + $minFutureHours);
            
            if ($isToday || $isWithinRequiredFutureHours) {
                $hourWeather = self::GetWeatherCondition($hourly['weather_code'][$i]);
                
                $processedHourly[] = [
                    'time' => date('H:i', $hourTimestamp),
                    'temp' => round($hourly['temperature_2m'][$i]),
                    'type' => $hourWeather['type'],
                    'condition' => $hourWeather['condition'] ?? $hourWeather['text'], 
                    'isCurrentHour' => ($i === $currentHourIndex),
                    'isTomorrow' => !$isToday 
                ];
            }
        }
        
        $processedDaily = [];
        $dayNames = ['امروز', 'فردا'];
        
        $dailyCount = isset($daily['time']) ? count($daily['time']) : 0;
        for ($i = 0; $i < min(7, $dailyCount); $i++) {
            $dayWeather = self::GetWeatherCondition($daily['weather_code'][$i]);
            $dayTimestamp = strtotime($daily['time'][$i]);
            
            $dayName = $dayNames[$i] ?? self::GetPersianDayName(date('w', $dayTimestamp));
            
            $processedDaily[] = [
                'day' => $dayName,
                'condition' => $dayWeather['text'],
                'min' => round($daily['temperature_2m_min'][$i]),
                'max' => round($daily['temperature_2m_max'][$i]),
                'type' => $dayWeather['type'],
            ];
        }
        
        return [
            'current' => $processedCurrent,
            'hourlyData' => $processedHourly,
            'dailyData' => $processedDaily,
        ];
    }

    public static function ProcessWeatherBatchData($rawData)
    {
        $current = $rawData['current'];
        $hourly = $rawData['hourly'];
        $daily = $rawData['daily'];
        
        $currentWeather = self::GetWeatherCondition($current['weather_code']);
        $currentTimestamp = strtotime($current['time']);
        
        $processedCurrent = [
            'day' => self::GetPersianDayName(date('w', $currentTimestamp)),
            'date' => self::ToPersianDate($currentTimestamp),
            'temp' => round($current['temperature_2m']),
            'condition' => $currentWeather['condition'],
            'type' => $currentWeather['type'],
            'text' => $currentWeather['text'],
            'description' => self::GenerateDescription($current, $hourly),
            'wind' => round($current['wind_speed_10m']),
            'humidity' => $current['relative_humidity_2m'],
            'pressure' => isset($current['surface_pressure']) ? round($current['surface_pressure']) : 'نامشخص',
            'uvIndex' => self::GetUVIndexText($hourly['uv_index'][0] ?? 0),
            'precipitation' => isset($current['precipitation']) ? $current['precipitation'] : '۰ م‌م',
        ];
        
        $currentHourIndex = 0;
        $currentDateString = date('Y-m-d', $currentTimestamp);
        
        foreach ($hourly['time'] as $index => $time) {
            if (strtotime($time) >= $currentTimestamp) {
                $currentHourIndex = $index;
                break;
            }
        }

        $minFutureHours = 10;
        
        $processedHourly = [];
        foreach ($hourly['time'] as $i => $timeStr) {
            $hourTimestamp = strtotime($timeStr);
            $isToday = (date('Y-m-d', $hourTimestamp) === $currentDateString);
            
            // شرط اول: آیا این ساعت متعلق به امروز است؟
            // شرط دوم: آیا این ساعت در بازه 10 ساعت آینده از زمان فعلی قرار دارد؟
            $isWithinRequiredFutureHours = ($i >= $currentHourIndex && $i <= $currentHourIndex + $minFutureHours);
            
            if ($isToday || $isWithinRequiredFutureHours) {
                $hourWeather = self::GetWeatherCondition($hourly['weather_code'][$i]);
                
                $processedHourly[] = [
                    'time' => date('H:i', $hourTimestamp),
                    'temp' => round($hourly['temperature_2m'][$i]),
                    'type' => $hourWeather['type'],
                    'condition' => $hourWeather['condition'] ?? $hourWeather['text'], 
                    'isCurrentHour' => ($i === $currentHourIndex),
                    'isTomorrow' => !$isToday 
                ];
            }
        }
        
        $processedDaily = [];
        $dayNames = ['امروز', 'فردا'];
        
        $dailyCount = isset($daily['time']) ? count($daily['time']) : 0;
        for ($i = 0; $i < min(7, $dailyCount); $i++) {
            $dayWeather = self::GetWeatherCondition($daily['weather_code'][$i]);
            $dayTimestamp = strtotime($daily['time'][$i]);
            
            $dayName = $dayNames[$i] ?? self::GetPersianDayName(date('w', $dayTimestamp));
            
            $processedDaily[] = [
                'day' => $dayName,
                'date' => self::ToPersianDate($dayTimestamp),
                'condition' => $dayWeather['text'],
                'min' => round($daily['temperature_2m_min'][$i]),
                'max' => round($daily['temperature_2m_max'][$i]),
                'type' => $dayWeather['type'],
            ];
        }
        
        return [
            'current' => $processedCurrent,
            'hourlyData' => $processedHourly,
            'dailyData' => $processedDaily,
            'metadata' => [
                'processedAt' => now()->toIso8601String(),
            ],
        ];
    }


}
