<?php

namespace App\Livewire\WorkTypes;

use App\Livewire\Concerns\HasCatalogToast;
use App\Livewire\Forms\WorkTypeForm;
use App\Models\Project;
use App\Models\WorkType;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Contracts\View\View;
use Illuminate\Support\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' => 'Tipos de Trabajo', 'header' => 'Tipos de Trabajo'])]
#[Title('Tipos de Trabajo')]
class WorkTypeIndex extends Component
{
    use HasCatalogToast;
    use WithPagination;

    public WorkTypeForm $form;

    public string $search = '';

    public int $perPage = 10;

    public bool $showModal = false;

    public bool $isEditing = false;

    public ?int $workTypeId = null;

    public bool $showDeleteConfirm = false;

    public ?int $deleteWorkTypeId = null;

    /** Si el tipo ya tiene OT, no se puede cambiar el proyecto. */
    public bool $canEditWorkTypeProject = true;

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

    /** @return LengthAwarePaginator<int, WorkType> */
    #[Computed]
    public function workTypes()
    {
        return WorkType::query()
            ->with('project')
            ->when($this->search, fn ($query) => $query->where('name', 'like', '%'.$this->search.'%'))
            ->withCount('works')
            ->orderBy('name')
            ->paginate($this->perPage);
    }

    /** @return Collection<int, Project> */
    #[Computed]
    public function projectsForSelect(): Collection
    {
        return Project::query()->orderBy('name')->get();
    }

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

    #[Computed]
    public function activeWorkTypes(): int
    {
        return WorkType::query()->where('status', true)->count();
    }

    #[Computed]
    public function inactiveWorkTypes(): int
    {
        return WorkType::query()->where('status', false)->count();
    }

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

    public function openEdit(int $id): void
    {
        $workType = WorkType::query()->withCount('works')->find($id);

        if (! $workType) {
            $this->showToastMessage('Tipo de trabajo no encontrado.', 'error');

            return;
        }

        $this->authorize('update', $workType);
        $this->workTypeId = $workType->id;
        $this->isEditing = true;
        $this->canEditWorkTypeProject = (int) $workType->works_count === 0;
        $this->form->fillFromModel($workType);
        $this->resetErrorBag();
        $this->showModal = true;
    }

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

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

        try {
            if ($this->isEditing) {
                $workType = WorkType::query()->findOrFail($this->workTypeId);
                $payload = [
                    'name' => trim($this->form->name),
                    'status' => $this->form->status,
                ];
                if ($this->canEditWorkTypeProject) {
                    $payload['project_id'] = $this->form->project_id;
                }
                $workType->update($payload);
                $message = 'Tipo de trabajo actualizado correctamente.';
            } else {
                WorkType::query()->create([
                    'project_id' => $this->form->project_id,
                    'name' => trim($this->form->name),
                    'status' => $this->form->status,
                ]);
                $message = 'Tipo de trabajo registrado correctamente.';
            }

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

    public function confirmDelete(int $id): void
    {
        $workType = WorkType::query()->withCount('works')->find($id);

        if (! $workType) {
            $this->showToastMessage('Tipo de trabajo no encontrado.', 'error');

            return;
        }

        if ($workType->works_count > 0) {
            $this->showToastMessage('No se puede eliminar: tiene trabajos asociados.', 'warning');

            return;
        }

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

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

        $workType = WorkType::query()->find($this->deleteWorkTypeId);

        if (! $workType) {
            $this->closeDeleteModal();
            $this->showToastMessage('Tipo de trabajo no encontrado.', 'error');

            return;
        }

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

        if ($workType->works()->count() > 0) {
            $this->closeDeleteModal();
            $this->showToastMessage('No se puede eliminar: el tipo de trabajo esta en uso.', 'warning');

            return;
        }

        $workType->delete();
        $this->closeDeleteModal();
        $this->resetPage();
        $this->showToastMessage('Tipo de trabajo eliminado correctamente.', 'success');
    }

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

    public function closeDeleteModal(): void
    {
        $this->showDeleteConfirm = false;
        $this->deleteWorkTypeId = 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.work-types.index');
    }
}
