<?php

namespace App\Livewire\HR;

use App\Domain\HR\Enums\EmployeeStatus;
use App\Domain\HR\Enums\EmploymentType;
use App\Domain\HR\Models\Employee;
use App\Domain\Identity\Services\PermissionService;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Livewire\Concerns\WithSorting;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

#[Layout('layouts.app')]
#[Title('الموظفين')]
class EmployeeList extends Component
{
    use WithPagination, WithSorting, UsesBranchScope;

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

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

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

    /**
     * An extra branch narrowing, meaningful only in all-branches mode.
     *
     * It used to be the list's only branch condition, which made ?branchId=7 —
     * or clearing it — a one-click escape from the branch the user is actually
     * in. Employee now carries BranchScope, so the boundary is enforced in the
     * model and this is a convenience filter on top of it; branchFilter()
     * still checks the value against what the user may see, because a public
     * property is settable from the browser.
     */
    #[Url]
    public string $branchId = '';

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

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

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

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

    public function render()
    {
        $query = Employee::with(['person', 'branch'])
            ->orderBy($this->sortBy, $this->sortDir);

        $query = app(PermissionService::class)->applyScope($query, auth()->user(), 'employees.list');

        if ($this->search) {
            $search = $this->search;
            $query->where(function ($q) use ($search) {
                $q->where('employee_number', 'ilike', "%{$search}%")
                    ->orWhereHas('person', function ($pq) use ($search) {
                        $pq->where('name_ar', 'ilike', "%{$search}%")
                            ->orWhere('name', 'ilike', "%{$search}%")
                            ->orWhere('national_id', 'ilike', "%{$search}%");
                    });
            });
        }

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

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

        // NOT a branch condition on its own: BranchScope already narrowed this
        // to the active branch, and Employee is shared-scoped so a null
        // branch_id (academy-wide staff) is deliberately included. This is only
        // a further narrowing, meaningful in all-branches mode.
        //
        // Written out rather than forBranch(): that helper drops the global
        // scope and hard-filters branch_id = :id, which on a shared table hides
        // every academy-wide employee — the exact rows the list is supposed to
        // keep. The OR NULL has to be spelled out here.
        if ($branchFilter = $this->branchFilter()) {
            $query->where(fn ($q) => $q->where('employees.branch_id', $branchFilter)
                ->orWhereNull('employees.branch_id'));
        }

        return view('livewire.hr.employee-list', [
            'employees' => $query->paginate(20),
            'statuses' => EmployeeStatus::cases(),
            'employmentTypes' => EmploymentType::cases(),
            'branches' => $this->selectableBranches(),
        ]);
    }

    /**
     * The branch the user asked to narrow to, or null.
     *
     * Only a branch they may actually pick counts — selectableBranches() is one
     * entry unless they are genuinely in all-branches mode, so a hand-typed
     * ?branchId= from another branch resolves to null and changes nothing.
     */
    private function branchFilter(): ?int
    {
        if ($this->branchId === '') {
            return null;
        }

        $id = (int) $this->branchId;

        return $this->selectableBranches()->contains('id', $id) ? $id : null;
    }
}
