<?php

namespace App\Services;

use App\Models\City;
use App\Models\State;
use App\Models\Zone;
use App\Models\ZoneRule;

class ZoneDetectionService
{
    /**
     * Detect zone from lat/lng by matching state + city in DB.
     * Returns the most suitable zone or null.
     */
    public function detectZone(float $lat, float $lng, ?string $cityName, ?string $stateName): ?Zone
    {
        // Resolve state
        $state = $this->resolveState($stateName);
        if (!$state) return null;

        // Resolve city
        $city = $this->resolveCity($cityName, $state->id);

        // Get default residential zone for city/state
        $query = Zone::where('state_id', $state->id)->where('is_active', true);
        if ($city) {
            // Prefer zones linked to this city's zone rules
            $zoneIds = ZoneRule::where('city_id', $city->id)->pluck('zone_id');
            if ($zoneIds->isNotEmpty()) {
                $query->whereIn('id', $zoneIds);
            }
        }

        return $query->where('zone_type', 'Residential')->first()
            ?? $query->first();
    }

    /**
     * Find the best matching rule for a zone + city + road width combination.
     * Tries city-specific rules first, then falls back to state-level defaults (city_id IS NULL).
     */
    public function findBestRule(int $zoneId, float $roadWidthM, ?int $cityId): ?ZoneRule
    {
        $baseQuery = fn(?int $cid) => ZoneRule::where('zone_id', $zoneId)
            ->where('is_active', true)
            ->when($cid !== null, fn($q) => $q->where('city_id', $cid), fn($q) => $q->whereNull('city_id'))
            ->where('road_width_min_m', '<=', $roadWidthM)
            ->where(function ($q) use ($roadWidthM) {
                $q->whereNull('road_width_max_m')
                  ->orWhere('road_width_max_m', '>=', $roadWidthM);
            })
            ->orderByDesc('road_width_min_m');

        // Try city-specific rules first
        if ($cityId) {
            $rule = $baseQuery($cityId)->first();
            if ($rule) return $rule;
        }

        // Fallback to state-level defaults (city_id IS NULL)
        return $baseQuery(null)->first();
    }

    /**
     * Check fundamental restriction flags for a location.
     * These are indicative checks based on lat/lng bounds (not PostGIS).
     */
    public function checkRestrictions(float $lat, float $lng): array
    {
        return [
            'crz'             => $this->isCrzZone($lat, $lng),
            'flood_zone'      => false, // Phase 2: NDMA data
            'eco_sensitive'   => false, // Phase 2: MOEF data
            'heritage_zone'   => false, // Phase 2: ASI data
            'nhai_buffer'     => false, // Phase 2: NHAI data
            'airport_funnel'  => false, // Phase 2: DGCA data
            'remarks'         => [],
        ];
    }

    /**
     * Rough CRZ check: within ~5km of coastline (simplified bounding boxes).
     * Phase 2 will replace with actual CRZ GIS data.
     */
    private function isCrzZone(float $lat, float $lng): bool
    {
        // Conservative coastline proximity bands for India (very simplified)
        $coastalBands = [
            // [lat_min, lat_max, lng_min, lng_max, description]
            [8.0,  23.5, 72.5, 73.5, 'Maharashtra/Gujarat coast'],
            [8.0,  13.5, 77.0, 80.5, 'Tamil Nadu coast'],
            [13.5, 20.0, 79.5, 80.5, 'Andhra Pradesh coast'],
            [13.5, 15.5, 74.0, 75.0, 'Goa coast'],
        ];

        foreach ($coastalBands as $band) {
            // Check if within rough coastal band AND within 500m of sea
            if ($lat >= $band[0] && $lat <= $band[1] && $lng >= $band[2] && $lng <= $band[3]) {
                // This is a rough band — Phase 2 will use actual CRZ shapefiles
                return false; // Don't flag by default at MVP; needs real data
            }
        }
        return false;
    }

    public function resolveState(?string $name): ?State
    {
        if (!$name) return null;
        return State::where('is_active', true)
            ->where(function ($q) use ($name) {
                $q->whereRaw('LOWER(name) = ?', [strtolower($name)])
                  ->orWhereRaw('LOWER(code) = ?', [strtolower($name)]);
            })->first();
    }

    public function resolveCity(?string $name, int $stateId): ?City
    {
        if (!$name) return null;

        // Normalize common aliases
        $aliases = [
            'mumbai'     => ['bombay', 'mumbai city', 'greater mumbai'],
            'bengaluru'  => ['bangalore'],
            'delhi'      => ['new delhi'],
            'kolkata'    => ['calcutta'],
            'chennai'    => ['madras'],
        ];

        $normalized = strtolower(trim($name));
        foreach ($aliases as $canonical => $alts) {
            if (in_array($normalized, $alts)) {
                $normalized = $canonical;
                break;
            }
        }

        return City::where('state_id', $stateId)
            ->where('is_active', true)
            ->whereRaw('LOWER(name) LIKE ?', ['%' . $normalized . '%'])
            ->first();
    }
}
