<?php

namespace App\Livewire\Documents;

use App\Domain\Document\Enums\DocumentStatus;
use App\Domain\Document\Enums\DocumentType;
use App\Domain\Document\Models\Document;
use App\Domain\HR\Models\Employee;
use App\Domain\HR\Models\Trainer;
use App\Domain\Identity\Models\Person;
use App\Domain\Participant\Models\Participant;
use App\Livewire\Concerns\WithSorting;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

#[Layout('layouts.app')]
#[Title('اعتماد المستندات')]
class DocumentApprovalList extends Component
{
    use WithPagination, WithSorting;

    #[Url]
    public string $search = '';

    #[Url]
    public string $status = 'pending';

    #[Url]
    public string $documentType = '';

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

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

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

    public function render()
    {
        $this->authorize('documents.approve');

        // No branch clause here, deliberately. `documents` now carries its own
        // branch_id and Document uses the strict BranchScope, so this query is
        // already narrowed to the active branch.
        //
        // The clause that used to sit here filtered by walking the
        // `documentable` morph into Participant only. That did narrow the
        // branch, but it also silently emptied the queue of every employee,
        // trainer and person document the moment a branch was selected — a
        // pending medical certificate for a coach simply never appeared for
        // anyone to approve. Re-adding a manual branch filter would bring that
        // back; the scope covers every morph type without one.
        $query = Document::with(['documentable', 'uploader'])
            ->orderBy($this->sortBy, $this->sortDir);

        if ($this->status) {
            $query->where('status', $this->status);
        }

        if ($this->documentType) {
            $query->where('document_type', $this->documentType);
        }

        if ($this->search) {
            $search = $this->search;

            $query->where(function (Builder $q) use ($search) {
                // Only a Person carries the name columns. A participant, an
                // employee and a trainer each hang theirs off `person`, so the
                // wildcard morph search that used to sit here asked
                // participants.name_ar for a column that table has never had —
                // every search on this screen came back as a 42703, whatever
                // branch you were in.
                $q->where('original_filename', 'ilike', "%{$search}%")
                    ->orWhereHasMorph(
                        'documentable',
                        [Person::class],
                        fn (Builder $mq) => $this->searchByName($mq, $search)
                    )
                    ->orWhereHasMorph(
                        'documentable',
                        [Participant::class, Employee::class, Trainer::class],
                        fn (Builder $mq) => $mq->whereHas(
                            'person',
                            fn (Builder $pq) => $this->searchByName($pq, $search)
                        )
                    );
            });
        }

        return view('livewire.documents.document-approval-list', [
            'documents' => $query->paginate(20),
            'statuses' => DocumentStatus::cases(),
            'documentTypes' => DocumentType::cases(),
        ]);
    }

    /**
     * Grouped so the OR cannot escape into the surrounding clause and widen
     * the result set past the branch and status filters around it.
     */
    private function searchByName(Builder $query, string $search): void
    {
        $query->where(function (Builder $q) use ($search) {
            $q->where('name_ar', 'ilike', "%{$search}%")
                ->orWhere('name', 'ilike', "%{$search}%");
        });
    }
}
