<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;

class GeoLocationService
{
    /**
     * Detect user location based on IP address and other factors
     */
    public function detectUserLocation($request)
    {
        $ip = $request->ip();
        $browserLang = $request->header('Accept-Language');
        $gpsCoords = $request->input('gps_coordinates');

        // Try multiple methods to detect location
        $location = $this->getGeoLocationFromIP($ip);
        
        // If IP detection fails, try browser language
        if (!$location || !$location['country']) {
            $location = $this->getCountryFromLanguage($browserLang);
        }
        
        // If GPS coordinates are available, use them for more accuracy
        if ($gpsCoords && isset($gpsCoords['latitude']) && isset($gpsCoords['longitude'])) {
            $gpsLocation = $this->getCountryFromCoordinates($gpsCoords['latitude'], $gpsCoords['longitude']);
            if ($gpsLocation && $gpsLocation['country']) {
                $location = $gpsLocation;
            }
        }

        // Set default values if detection failed
        $location = $location ?? [
            'country' => 'USA',
            'currency' => 'USD',
            'timezone' => 'UTC',
            'city' => 'Unknown',
            'state' => 'Unknown'
        ];

        // Get currency for detected country
        $location['currency'] = $this->getCurrencyForCountry($location['country']);
        
        return $location;
    }

    /**
     * Get geolocation from IP address using external API
     */
    private function getGeoLocationFromIP($ip)
    {
        // Cache location for 1 hour to avoid API rate limits
        $cacheKey = "geo_location_{$ip}";
        
        return Cache::remember($cacheKey, 3600, function() use ($ip) {
            try {
                // Use ipapi.co for free geolocation
                $response = Http::get("https://ipapi.co/{$ip}/json/");
                
                if ($response->successful()) {
                    $data = $response->json();
                    
                    return [
                        'country' => $data['country_name'] ?? $data['country_code'] ?? null,
                        'country_code' => $data['country_code'] ?? null,
                        'city' => $data['city'] ?? null,
                        'state' => $data['region'] ?? null,
                        'latitude' => $data['latitude'] ?? null,
                        'longitude' => $data['longitude'] ?? null,
                        'timezone' => $data['timezone'] ?? 'UTC',
                        'currency' => $data['currency'] ?? null,
                    ];
                }
            } catch (\Exception $e) {
                // Log error but don't fail
                \Log::warning('GeoLocation API failed for IP: ' . $ip, ['error' => $e->getMessage()]);
            }

            return null;
        });
    }

    /**
     * Get country from browser language header
     */
    private function getCountryFromLanguage($languageHeader)
    {
        if (!$languageHeader) {
            return null;
        }

        // Parse Accept-Language header
        $languages = explode(',', $languageHeader);
        $primaryLang = trim(explode(';', $languages[0])[0]);

        // Map language codes to countries
        $languageToCountry = [
            'en-US' => ['USA', 'USD'],
            'en-GB' => ['UK', 'GBP'],
            'en-CA' => ['Canada', 'CAD'],
            'fr-CA' => ['Canada', 'CAD'],
            'en-AU' => ['Australia', 'AUD'],
            'de-DE' => ['Germany', 'EUR'],
            'fr-FR' => ['France', 'EUR'],
            'es-ES' => ['Spain', 'EUR'],
            'pt-BR' => ['Brazil', 'BRL'],
            'hi-IN' => ['India', 'INR'],
            'en-IN' => ['India', 'INR'],
            'ja-JP' => ['Japan', 'JPY'],
            'zh-CN' => ['China', 'CNY'],
            'ar-SA' => ['Saudi Arabia', 'SAR'],
            'ru-RU' => ['Russia', 'RUB'],
        ];

        if (isset($languageToCountry[$primaryLang])) {
            $countryData = $languageToCountry[$primaryLang];
            return [
                'country' => $countryData[0],
                'currency' => $countryData[1],
                'timezone' => $this->getTimezoneForCountry($countryData[0]),
                'city' => 'Unknown',
                'state' => 'Unknown'
            ];
        }

        // Try language without region
        $langCode = explode('-', $primaryLang)[0];
        $countryMap = [
            'en' => ['USA', 'USD'],
            'fr' => ['France', 'EUR'],
            'de' => ['Germany', 'EUR'],
            'es' => ['Spain', 'EUR'],
            'pt' => ['Brazil', 'BRL'],
            'hi' => ['India', 'INR'],
            'ja' => ['Japan', 'JPY'],
            'zh' => ['China', 'CNY'],
            'ar' => ['Saudi Arabia', 'SAR'],
            'ru' => ['Russia', 'RUB'],
        ];

        if (isset($countryMap[$langCode])) {
            $countryData = $countryMap[$langCode];
            return [
                'country' => $countryData[0],
                'currency' => $countryData[1],
                'timezone' => $this->getTimezoneForCountry($countryData[0]),
                'city' => 'Unknown',
                'state' => 'Unknown'
            ];
        }

        return null;
    }

    /**
     * Get country from GPS coordinates
     */
    private function getCountryFromCoordinates($latitude, $longitude)
    {
        try {
            // Use OpenStreetMap Nominatim API for reverse geocoding
            $response = Http::get('https://nominatim.openstreetmap.org/reverse', [
                'format' => 'json',
                'lat' => $latitude,
                'lon' => $longitude,
                'addressdetails' => 1,
                'accept-language' => 'en'
            ]);

            if ($response->successful()) {
                $data = $response->json();
                
                if (isset($data['address'])) {
                    $address = $data['address'];
                    
                    return [
                        'country' => $address['country'] ?? null,
                        'country_code' => $address['country_code'] ?? null,
                        'city' => $address['city'] ?? $address['town'] ?? $address['village'] ?? null,
                        'state' => $address['state'] ?? null,
                        'latitude' => $latitude,
                        'longitude' => $longitude,
                        'timezone' => $this->getTimezoneForCountry($address['country'] ?? null),
                        'currency' => $this->getCurrencyForCountry($address['country'] ?? null),
                    ];
                }
            }
        } catch (\Exception $e) {
            \Log::warning('Reverse geocoding failed', ['error' => $e->getMessage()]);
        }

        return null;
    }

    /**
     * Get currency for country
     */
    public function getCurrencyForCountry($country)
    {
        if (!$country) {
            return 'USD'; // Default currency
        }

        $currencyMap = [
            'USA' => 'USD', 'United States' => 'USD',
            'Canada' => 'CAD', 'UK' => 'GBP', 'United Kingdom' => 'GBP',
            'Germany' => 'EUR', 'France' => 'EUR', 'Spain' => 'EUR',
            'Australia' => 'AUD', 'Brazil' => 'BRL', 'India' => 'INR',
            'Japan' => 'JPY', 'China' => 'CNY', 'Saudi Arabia' => 'SAR',
            'Russia' => 'RUB', 'Mexico' => 'MXN', 'Argentina' => 'ARS',
            'South Africa' => 'ZAR', 'Nigeria' => 'NGN', 'Egypt' => 'EGP',
            'Turkey' => 'TRY', 'Poland' => 'PLN', 'Netherlands' => 'EUR',
            'Italy' => 'EUR', 'Sweden' => 'SEK', 'Norway' => 'NOK',
            'Denmark' => 'DKK', 'Finland' => 'EUR', 'Switzerland' => 'CHF',
            'Austria' => 'EUR', 'Belgium' => 'EUR', 'Greece' => 'EUR',
            'Portugal' => 'EUR', 'Ireland' => 'EUR', 'New Zealand' => 'NZD',
        ];

        return $currencyMap[$country] ?? 'USD';
    }

    /**
     * Get timezone for country
     */
    private function getTimezoneForCountry($country)
    {
        $timezoneMap = [
            'USA' => 'America/New_York',
            'Canada' => 'America/Toronto',
            'UK' => 'Europe/London',
            'Germany' => 'Europe/Berlin',
            'France' => 'Europe/Paris',
            'Australia' => 'Australia/Sydney',
            'Brazil' => 'America/Sao_Paulo',
            'India' => 'Asia/Kolkata',
            'Japan' => 'Asia/Tokyo',
            'China' => 'Asia/Shanghai',
        ];

        return $timezoneMap[$country] ?? 'UTC';
    }

    /**
     * Get list of supported countries
     */
    public function getSupportedCountries()
    {
        return [
            'USA' => ['name' => 'United States', 'currency' => 'USD', 'timezone' => 'America/New_York'],
            'Canada' => ['name' => 'Canada', 'currency' => 'CAD', 'timezone' => 'America/Toronto'],
            'UK' => ['name' => 'United Kingdom', 'currency' => 'GBP', 'timezone' => 'Europe/London'],
            'Germany' => ['name' => 'Germany', 'currency' => 'EUR', 'timezone' => 'Europe/Berlin'],
            'France' => ['name' => 'France', 'currency' => 'EUR', 'timezone' => 'Europe/Paris'],
            'Australia' => ['name' => 'Australia', 'currency' => 'AUD', 'timezone' => 'Australia/Sydney'],
            'Brazil' => ['name' => 'Brazil', 'currency' => 'BRL', 'timezone' => 'America/Sao_Paulo'],
            'India' => ['name' => 'India', 'currency' => 'INR', 'timezone' => 'Asia/Kolkata'],
            'Japan' => ['name' => 'Japan', 'currency' => 'JPY', 'timezone' => 'Asia/Tokyo'],
            'Spain' => ['name' => 'Spain', 'currency' => 'EUR', 'timezone' => 'Europe/Madrid'],
        ];
    }

    /**
     * Validate country and currency combination
     */
    public function validateCountryCurrency($country, $currency)
    {
        $supportedCountries = $this->getSupportedCountries();
        
        if (!isset($supportedCountries[$country])) {
            return false;
        }

        return $supportedCountries[$country]['currency'] === $currency;
    }
}
