<?php

namespace App\Livewire\Location;

use Livewire\Component;
use App\Services\GeocodeService;
use App\Exceptions\GeocodingException;
use App\Exceptions\ValidationException;

class LocationSelectorComponent extends Component
{
    // Search State
    public string $searchQuery = '';
    public array $searchResults = [];
    public bool $isSearching = false;
    public ?string $validationError = null;

    // Location State
    public ?float $latitude = null;
    public ?float $longitude = null;
    public ?string $formattedAddress = null;
    public bool $isValidLocation = false;

    // UI State
    public bool $showSearchResults = false;
    public bool $isLoadingLocation = false;
    public string $mode = 'search'; // search|coordinates|current

    // Component Configuration
    protected $geocodeService;

    protected $listeners = [
        'mapLocationSelected' => 'handleMapLocation',
        'clearLocation' => 'clearSelection',
    ];

    public function mount(GeocodeService $geocodeService)
    {
        $this->geocodeService = $geocodeService;
    }

    public function render()
    {
        return view('livewire.location.location-selector');
    }

    public function updatedSearchQuery()
    {
        if (strlen($this->searchQuery) < 3) {
            $this->searchResults = [];
            $this->showSearchResults = false;
            return;
        }

        try {
            $this->isSearching = true;
            $this->searchResults = $this->geocodeService->geocode($this->searchQuery);
            $this->showSearchResults = true;
            $this->validationError = null;
        } catch (GeocodingException $e) {
            $this->validationError = $e->getMessage();
        } finally {
            $this->isSearching = false;
        }
    }

    public function selectLocation(array $location)
    {
        try {
            if (!isset($location['lat'], $location['lon'])) {
                throw new ValidationException('Invalid location data');
            }

            $this->setCoordinates($location['lat'], $location['lon']);
            $this->formattedAddress = $location['display_name'] ?? null;
            $this->showSearchResults = false;
            $this->searchQuery = '';
            $this->isValidLocation = true;
            $this->validationError = null;

            $this->dispatch('locationSelected', [
                'latitude' => $this->latitude,
                'longitude' => $this->longitude,
                'address' => $this->formattedAddress,
            ]);
        } catch (ValidationException $e) {
            $this->validationError = $e->getMessage();
            $this->isValidLocation = false;
        }
    }

    public function setCoordinates(float $lat, float $lon)
    {
        try {
            if (!$this->geocodeService->validateCoordinates($lat, $lon)) {
                throw new ValidationException('Invalid coordinates');
            }

            $this->latitude = $lat;
            $this->longitude = $lon;
            $this->isValidLocation = true;
            $this->validationError = null;

            $this->dispatch('coordinatesChanged', [
                'latitude' => $this->latitude,
                'longitude' => $this->longitude,
            ]);
        } catch (ValidationException $e) {
            $this->validationError = $e->getMessage();
            $this->isValidLocation = false;
        }
    }

    public function handleMapLocation($lat, $lon)
    {
        $this->setCoordinates($lat, $lon);
        
        try {
            $address = $this->geocodeService->reverseGeocode($lat, $lon);
            $this->formattedAddress = $address['display_name'] ?? null;
        } catch (GeocodingException $e) {
            $this->validationError = $e->getMessage();
        }
    }

    public function detectCurrentLocation()
    {
        $this->mode = 'current';
        $this->isLoadingLocation = true;
        $this->dispatch('requestCurrentLocation');
    }

    public function clearSelection()
    {
        $this->reset([
            'latitude',
            'longitude',
            'formattedAddress',
            'isValidLocation',
            'searchQuery',
            'searchResults',
            'showSearchResults',
            'validationError',
        ]);
        $this->mode = 'search';
    }

    public function switchMode(string $mode)
    {
        if (!in_array($mode, ['search', 'coordinates', 'current'])) {
            return;
        }

        $this->mode = $mode;
        $this->clearSelection();
        $this->dispatch('modeChanged', ['mode' => $mode]);
    }

    protected function rules()
    {
        return [
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'searchQuery' => 'nullable|string|min:3|max:200',
        ];
    }
}