<?php

namespace App\Livewire\Districts;

use App\Livewire\Concerns\HasCatalogToast;
use App\Livewire\Forms\DistrictForm;
use App\Models\District;
use App\Models\Province;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Collection;
use Livewire\Attributes\Computed;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;
use Livewire\WithPagination;
use Throwable;

#[Layout('layouts.app', ['title' => 'Distritos', 'header' => 'Distritos'])]
#[Title('Distritos')]
class DistrictIndex extends Component
{
    use HasCatalogToast;
    use WithPagination;

    public DistrictForm $form;

    public string $search = '';

    public int $perPage = 10;

    public bool $showModal = false;

    public bool $isEditing = false;

    public ?int $districtId = null;

    public bool $showDeleteConfirm = false;

    public ?int $deleteDistrictId = null;

    public function mount(): void
    {
        $this->authorize('viewAny', District::class);
    }

    /** @return LengthAwarePaginator<int, District> */
    #[Computed]
    public function districts()
    {
        return District::query()
            ->when($this->search, function ($query) {
                $query->where('name', 'like', '%'.$this->search.'%')
                    ->orWhereHas('province', fn ($q) => $q->where('name', 'like', '%'.$this->search.'%'))
                    ->orWhereHas('province.department', fn ($q) => $q->where('name', 'like', '%'.$this->search.'%'));
            })
            ->with(['province:id,name,department_id', 'province.department:id,name'])
            ->withCount('sites')
            ->orderBy('name')
            ->paginate($this->perPage);
    }

    /** @return Collection<int, Province> */
    #[Computed]
    public function provinces(): Collection
    {
        return Province::query()
            ->with('department:id,name')
            ->orderBy('name')
            ->get(['id', 'name', 'department_id']);
    }

    #[Computed]
    public function totalDistricts(): int
    {
        return District::query()->count();
    }

    #[Computed]
    public function districtsInUse(): int
    {
        return District::query()->has('sites')->count();
    }

    #[Computed]
    public function districtsWithoutUse(): int
    {
        return District::query()->doesntHave('sites')->count();
    }

    public function openCreate(): void
    {
        $this->authorize('create', District::class);
        $this->isEditing = false;
        $this->districtId = null;
        $this->form->resetForCreate();
        $this->resetErrorBag();
        $this->showModal = true;
    }

    public function openEdit(int $id): void
    {
        $district = District::query()->find($id);

        if (! $district) {
            $this->showToastMessage('Distrito no encontrado.', 'error');

            return;
        }

        $this->authorize('update', $district);
        $this->districtId = $district->id;
        $this->isEditing = true;
        $this->form->fillFromModel($district);
        $this->resetErrorBag();
        $this->showModal = true;
    }

    public function save(): void
    {
        if ($this->isEditing) {
            $district = District::query()->findOrFail($this->districtId);
            $this->authorize('update', $district);
        } else {
            $this->authorize('create', District::class);
        }

        $this->form->validate(
            $this->form->rules($this->isEditing ? $this->districtId : null),
            $this->form->validationMessages(),
        );

        try {
            if ($this->isEditing) {
                $district = District::query()->findOrFail($this->districtId);
                $district->update([
                    'name' => trim($this->form->name),
                    'province_id' => $this->form->province_id,
                ]);
                $message = 'Distrito actualizado correctamente.';
            } else {
                District::query()->create([
                    'name' => trim($this->form->name),
                    'province_id' => $this->form->province_id,
                ]);
                $message = 'Distrito registrado correctamente.';
            }

            $this->closeModal();
            $this->resetPage();
            $this->showToastMessage($message, 'success');
        } catch (Throwable $e) {
            report($e);
            $this->showToastMessage('No se pudo guardar el distrito.', 'error');
        }
    }

    public function confirmDelete(int $id): void
    {
        $district = District::query()->withCount('sites')->find($id);

        if (! $district) {
            $this->showToastMessage('Distrito no encontrado.', 'error');

            return;
        }

        if ($district->sites_count > 0) {
            $this->showToastMessage('No se puede eliminar: el distrito tiene sitios asociados.', 'warning');

            return;
        }

        $this->authorize('delete', $district);
        $this->deleteDistrictId = $id;
        $this->showDeleteConfirm = true;
    }

    public function destroy(): void
    {
        if ($this->deleteDistrictId === null) {
            return;
        }

        $district = District::query()->find($this->deleteDistrictId);

        if (! $district) {
            $this->closeDeleteModal();
            $this->showToastMessage('Distrito no encontrado.', 'error');

            return;
        }

        $this->authorize('delete', $district);

        if ($district->sites()->count() > 0) {
            $this->closeDeleteModal();
            $this->showToastMessage('No se puede eliminar: el distrito está en uso.', 'warning');

            return;
        }

        $district->delete();
        $this->closeDeleteModal();
        $this->resetPage();
        $this->showToastMessage('Distrito eliminado correctamente.', 'success');
    }

    public function closeModal(): void
    {
        $this->showModal = false;
        $this->isEditing = false;
        $this->districtId = null;
        $this->form->resetForCreate();
        $this->resetErrorBag();
    }

    public function closeDeleteModal(): void
    {
        $this->showDeleteConfirm = false;
        $this->deleteDistrictId = null;
    }

    public function resetSearch(): void
    {
        $this->search = '';
        $this->resetPage();
    }

    public function updatedSearch(): void
    {
        $this->resetPage();
    }

    public function updatedPerPage(): void
    {
        $this->resetPage();
    }

    public function render(): View
    {
        return view('livewire.districts.index');
    }
}
