<?php

namespace App\Services;

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

class GeocodingService
{
    private const NOMINATIM_BASE = 'https://nominatim.openstreetmap.org';
    private const CACHE_TTL = 3600 * 24; // 24 hours

    /**
     * Convert address string to lat/lng + structured address data.
     */
    public function geocode(string $address): ?array
    {
        $cacheKey = 'geocode_' . md5($address);

        return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($address) {
            try {
                $response = Http::withHeaders([
                    'User-Agent' => 'LandFeasibility/1.0 (contact@landfeasibility.in)',
                    'Accept-Language' => 'en',
                ])->timeout(10)->get(self::NOMINATIM_BASE . '/search', [
                    'q'              => $address . ', India',
                    'format'         => 'json',
                    'addressdetails' => 1,
                    'limit'          => 1,
                    'countrycodes'   => 'in',
                ]);

                if ($response->successful()) {
                    $results = $response->json();
                    if (!empty($results)) {
                        $r = $results[0];
                        $addr = $r['address'] ?? [];
                        return [
                            'latitude'  => (float) $r['lat'],
                            'longitude' => (float) $r['lon'],
                            'display'   => $r['display_name'] ?? $address,
                            'city'      => $addr['city'] ?? $addr['town'] ?? $addr['village'] ?? $addr['county'] ?? null,
                            'state'     => $addr['state'] ?? null,
                            'district'  => $addr['state_district'] ?? null,
                            'country'   => $addr['country'] ?? 'India',
                            'postcode'  => $addr['postcode'] ?? null,
                        ];
                    }
                }
            } catch (\Exception $e) {
                Log::warning('Geocoding failed: ' . $e->getMessage());
            }
            return null;
        });
    }

    /**
     * Convert lat/lng to structured address.
     */
    public function reverseGeocode(float $lat, float $lng): ?array
    {
        $cacheKey = 'revgeocode_' . round($lat, 4) . '_' . round($lng, 4);

        return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($lat, $lng) {
            try {
                $response = Http::withHeaders([
                    'User-Agent' => 'LandFeasibility/1.0 (contact@landfeasibility.in)',
                    'Accept-Language' => 'en',
                ])->timeout(10)->get(self::NOMINATIM_BASE . '/reverse', [
                    'lat'    => $lat,
                    'lon'    => $lng,
                    'format' => 'json',
                    'addressdetails' => 1,
                ]);

                if ($response->successful()) {
                    $r = $response->json();
                    $addr = $r['address'] ?? [];
                    return [
                        'display'   => $r['display_name'] ?? '',
                        'road'      => $addr['road'] ?? null,
                        'suburb'    => $addr['suburb'] ?? null,
                        'city'      => $addr['city'] ?? $addr['town'] ?? $addr['village'] ?? null,
                        'state'     => $addr['state'] ?? null,
                        'district'  => $addr['state_district'] ?? null,
                        'postcode'  => $addr['postcode'] ?? null,
                        'country'   => $addr['country'] ?? 'India',
                    ];
                }
            } catch (\Exception $e) {
                Log::warning('Reverse geocoding failed: ' . $e->getMessage());
            }
            return null;
        });
    }

    /**
     * Get nearest road width from OpenStreetMap Overpass API.
     * Returns estimated metres or null.
     */
    public function getRoadWidth(float $lat, float $lng): ?float
    {
        $cacheKey = 'road_width_' . round($lat, 4) . '_' . round($lng, 4);

        return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($lat, $lng) {
            try {
                $delta = 0.001; // ~100m search radius
                $query = "[out:json][timeout:15];
                way(around:100,{$lat},{$lng})[highway~\"^(primary|secondary|tertiary|residential|unclassified|trunk|motorway|service)$\"];
                out tags 1;";

                $response = Http::withHeaders([
                    'User-Agent' => 'LandFeasibility/1.0',
                ])->timeout(15)->post('https://overpass-api.de/api/interpreter', [
                    'data' => $query,
                ]);

                if ($response->successful()) {
                    $data = $response->json();
                    $elements = $data['elements'] ?? [];
                    if (!empty($elements)) {
                        $tags = $elements[0]['tags'] ?? [];
                        // OSM width tag (in metres)
                        if (isset($tags['width'])) {
                            return (float) preg_replace('/[^0-9.]/', '', $tags['width']);
                        }
                        // Estimate from highway classification
                        return $this->estimateWidthFromHighwayType($tags['highway'] ?? 'residential');
                    }
                }
            } catch (\Exception $e) {
                Log::warning('Road width detection failed: ' . $e->getMessage());
            }
            return null;
        });
    }

    private function estimateWidthFromHighwayType(string $type): float
    {
        return match ($type) {
            'motorway', 'trunk'         => 30.0,
            'primary'                   => 18.0,
            'secondary'                 => 12.0,
            'tertiary'                  => 9.0,
            'residential', 'unclassified' => 6.0,
            'service'                   => 4.5,
            default                     => 6.0,
        };
    }
}
