<?php

namespace App\Http\Controllers;

use App\Models\FranchiseZone;
use App\Models\StateMap;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;

class MonitorController extends Controller
{
    public function monitor(): View
    {
        $this->mustBeMonitoring();

        return view('monitor.index', [
            'states' => StateMap::withCount('franchiseZones')->orderBy('name')->get(),
        ]);
    }

    public function mapping(): View
    {
        $this->mustBeMonitoring();

        return view('monitor.mapping', [
            'states' => StateMap::orderBy('name')->get(),
        ]);
    }

    public function trafficMap(StateMap $stateMap): View
    {
        $this->mustBeMonitoring();

        return view('monitor.traffic-map', [
            'state' => $stateMap,
            'states' => StateMap::orderBy('name')->get(),
        ]);
    }

    public function franchise(StateMap $stateMap): View
    {
        $this->mustBeMonitoring();
        $this->ensureDefaultZones($stateMap);

        return view('monitor.franchise-zones', [
            'state' => $stateMap->fresh('franchiseZones'),
        ]);
    }

    public function saveFranchiseZones(Request $request, StateMap $stateMap): RedirectResponse
    {
        $this->mustBeMonitoring();
        $this->ensureDefaultZones($stateMap);

        $validated = $request->validate([
            'zones' => ['required', 'array', 'size:4'],
            'zones.*.id' => ['required', 'integer', 'exists:franchise_zones,id'],
            'zones.*.boundary_start_lat' => ['required', 'numeric', 'between:-90,90'],
            'zones.*.boundary_start_lng' => ['required', 'numeric', 'between:-180,180'],
            'zones.*.boundary_end_lat' => ['required', 'numeric', 'between:-90,90'],
            'zones.*.boundary_end_lng' => ['required', 'numeric', 'between:-180,180'],
            'zones.*.center_lat' => ['required', 'numeric', 'between:-90,90'],
            'zones.*.center_lng' => ['required', 'numeric', 'between:-180,180'],
            'zones.*.radius_km' => ['required', 'numeric', 'min:1', 'max:1000'],
        ]);

        DB::transaction(function () use ($validated, $stateMap): void {
            foreach ($validated['zones'] as $zoneData) {
                $zone = FranchiseZone::where('state_map_id', $stateMap->id)->findOrFail($zoneData['id']);
                $zone->update([
                    'boundary_start_lat' => $zoneData['boundary_start_lat'],
                    'boundary_start_lng' => $zoneData['boundary_start_lng'],
                    'boundary_end_lat' => $zoneData['boundary_end_lat'],
                    'boundary_end_lng' => $zoneData['boundary_end_lng'],
                    'center_lat' => $zoneData['center_lat'],
                    'center_lng' => $zoneData['center_lng'],
                    'radius_km' => $zoneData['radius_km'],
                    'polygon_json' => $this->makeZonePolygon(
                        (float) $zoneData['center_lat'],
                        (float) $zoneData['center_lng'],
                        (float) $zoneData['radius_km']
                    ),
                ]);
            }
        });

        return back()->with('success', 'Franchise zone boundaries saved for '.$stateMap->name.'.');
    }

    private function ensureDefaultZones(StateMap $stateMap): void
    {
        if ($stateMap->franchiseZones()->count() >= 4) {
            return;
        }

        $lat = (float) $stateMap->latitude;
        $lng = (float) $stateMap->longitude;
        $offset = 0.35;
        $radius = 75.00;

        $defaults = [
            ['zone_number' => 1, 'zone_name' => 'Zone 1 - North West', 'center_lat' => $lat + $offset, 'center_lng' => $lng - $offset, 'boundary_start_lat' => $lat + ($offset * 2), 'boundary_start_lng' => $lng - ($offset * 2), 'boundary_end_lat' => $lat, 'boundary_end_lng' => $lng],
            ['zone_number' => 2, 'zone_name' => 'Zone 2 - North East', 'center_lat' => $lat + $offset, 'center_lng' => $lng + $offset, 'boundary_start_lat' => $lat + ($offset * 2), 'boundary_start_lng' => $lng, 'boundary_end_lat' => $lat, 'boundary_end_lng' => $lng + ($offset * 2)],
            ['zone_number' => 3, 'zone_name' => 'Zone 3 - South West', 'center_lat' => $lat - $offset, 'center_lng' => $lng - $offset, 'boundary_start_lat' => $lat, 'boundary_start_lng' => $lng - ($offset * 2), 'boundary_end_lat' => $lat - ($offset * 2), 'boundary_end_lng' => $lng],
            ['zone_number' => 4, 'zone_name' => 'Zone 4 - South East', 'center_lat' => $lat - $offset, 'center_lng' => $lng + $offset, 'boundary_start_lat' => $lat, 'boundary_start_lng' => $lng, 'boundary_end_lat' => $lat - ($offset * 2), 'boundary_end_lng' => $lng + ($offset * 2)],
        ];

        foreach ($defaults as $zone) {
            $stateMap->franchiseZones()->updateOrCreate(
                ['zone_number' => $zone['zone_number']],
                array_merge($zone, [
                    'radius_km' => $radius,
                    'polygon_json' => $this->makeZonePolygon($zone['center_lat'], $zone['center_lng'], $radius),
                ])
            );
        }
    }

    private function makeZonePolygon(float $centerLat, float $centerLng, float $radiusKm): array
    {
        $latDelta = $radiusKm / 111;
        $lngDelta = $radiusKm / max(1, 111 * cos(deg2rad($centerLat)));

        return [
            [$centerLat + $latDelta, $centerLng - $lngDelta],
            [$centerLat + $latDelta, $centerLng + $lngDelta],
            [$centerLat - $latDelta, $centerLng + $lngDelta],
            [$centerLat - $latDelta, $centerLng - $lngDelta],
        ];
    }

    private function mustBeMonitoring(): void
    {
        abort_unless(Auth::user()?->isMonitoring(), 403, 'Only Monitoring users can access this page.');
    }
}
