<?php

namespace App\Livewire\Inventory;

use App\Domain\Inventory\Models\Warehouse;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('المستودعات')]
class WarehouseForm extends Component
{
    use UsesBranchScope;

    public ?Warehouse $warehouse = null;
    public bool $editing = false;

    public string $name_ar = '';
    public string $name = '';
    public string $code = '';
    public string $type = 'main';
    public ?int $branch_id = null;
    public ?int $manager_id = null;
    public string $address = '';
    public bool $is_active = true;

    public function mount(?Warehouse $warehouse = null): void
    {
        $this->authorize('inventory.create');

        if ($warehouse && $warehouse->exists) {
            $this->authorize('inventory.update');
            $this->warehouse = $warehouse;
            $this->editing = true;

            $this->name_ar = $warehouse->name_ar ?? '';
            $this->name = $warehouse->name ?? '';
            $this->code = $warehouse->code ?? '';
            $this->type = $warehouse->type->value ?? 'main';
            $this->branch_id = $warehouse->branch_id;
            $this->manager_id = $warehouse->manager_id;
            $this->address = $warehouse->address ?? '';
            $this->is_active = $warehouse->is_active;
        }
    }

    public function rules(): array
    {
        // unique:/exists: are raw table queries, invisible to both the academy
        // and the branch scope. warehouses.code is unique(academy_id, code), so
        // that rule is academy-scoped to match the constraint exactly.
        $academyId = app('current_academy')->id;

        $uniqueCode = Rule::unique('warehouses', 'code')->where('academy_id', $academyId);

        if ($this->editing) {
            $uniqueCode = $uniqueCode->ignore($this->warehouse->id);
        }

        return [
            'name_ar' => 'required|string|max:255',
            'name' => 'nullable|string|max:255',
            'code' => ['required', 'string', 'max:20', $uniqueCode],
            'type' => 'required|in:main,sub,transit,returns',
            // Not exists:branches,id — that accepted any branch in the academy
            // and $branch_id is a plain public property, so a warehouse (and
            // every level and movement hanging off it) could be moved into
            // another branch from the browser. selectableBranches() is one entry
            // unless the user is genuinely in all-branches mode. Required
            // rather than nullable: the row is strictly branch-scoped, so an
            // empty picker would file the store against no branch and hide it
            // from every one of them.
            'branch_id' => ['required', Rule::in($this->selectableBranches()->pluck('id')->all())],
            'manager_id' => ['nullable', Rule::in($this->selectableManagerIds())],
            'address' => 'nullable|string|max:500',
            'is_active' => 'boolean',
        ];
    }

    /**
     * Staff who may be put in charge of a warehouse in this branch.
     *
     * `users` has no branch_id — a user's branch lives on the role_user pivot —
     * so there is no global scope to lean on here and the predicate has to be
     * written out. Users whose role carries no branch (academy-wide admins)
     * stay eligible; excluding them would empty the picker on most tenants.
     */
    private function managerQuery(): Builder
    {
        $branchId = $this->getActiveBranchId();

        // `users` has no `is_active` column — it has `status`, constrained to
        // active/inactive/suspended/pending. The old condition made
        // /inventory/warehouses/create throw a 42703 on every load, so the
        // screen has never opened.
        return User::where('status', 'active')
            ->when($branchId, fn ($q) => $q->whereHas('roles', fn ($r) => $r->where(
                fn ($p) => $p->whereNull('role_user.branch_id')->orWhere('role_user.branch_id', $branchId)
            )))
            ->orderBy('name_ar');
    }

    /**
     * @return array<int, int>
     */
    private function selectableManagerIds(): array
    {
        $ids = $this->managerQuery()->pluck('id')->all();

        // The manager already on record stays valid even if they have since
        // moved branch — otherwise editing the address of a warehouse whose
        // manager no longer qualifies would be impossible without also
        // reassigning them.
        if ($this->editing && $this->warehouse->manager_id) {
            $ids[] = (int) $this->warehouse->manager_id;
        }

        return $ids;
    }

    public function messages(): array
    {
        return [
            'name_ar.required' => 'اسم المستودع بالعربية مطلوب',
            'name_ar.max' => 'اسم المستودع يجب ألا يتجاوز 255 حرف',
            'code.required' => 'كود المستودع مطلوب',
            'code.unique' => 'كود المستودع مستخدم بالفعل',
            'code.max' => 'كود المستودع يجب ألا يتجاوز 20 حرف',
            'type.required' => 'نوع المستودع مطلوب',
            'type.in' => 'نوع المستودع غير صالح',
            'branch_id.required' => 'يجب اختيار الفرع',
            'branch_id.in' => 'الفرع غير متاح',
            'manager_id.in' => 'المدير غير متاح',
        ];
    }

    public function save(): void
    {
        $this->validate();

        try {
            $data = [
                'name_ar' => $this->name_ar,
                'name' => $this->name ?: null,
                'code' => $this->code,
                'type' => $this->type,
                'branch_id' => $this->branch_id,
                'manager_id' => $this->manager_id,
                'address' => $this->address ?: null,
                'is_active' => $this->is_active,
            ];

            if ($this->editing) {
                $this->warehouse->update($data);
                session()->flash('success', __('تم تحديث المستودع بنجاح'));
            } else {
                $data['created_by'] = auth()->id();
                Warehouse::create($data);
                session()->flash('success', __('تم إنشاء المستودع بنجاح'));
            }

            $this->redirect(route('inventory.warehouses'), navigate: true);
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        }
    }

    public function render()
    {
        return view('livewire.inventory.warehouse-form', [
            // The topbar switcher is the branch selector. selectableBranches()
            // returns one entry unless the user is actually in all-branches
            // mode, and the view drops the <select> entirely in that case —
            // a second branch control beside the switcher is how another
            // branch's rows kept reaching screens that were otherwise filtered.
            'branches' => $this->selectableBranches(),
            'managers' => $this->managerQuery()->get(['id', 'name_ar', 'name']),
            'typeOptions' => [
                'main' => 'رئيسي',
                'sub' => 'فرعي',
                'transit' => 'نقل',
                'returns' => 'مرتجعات',
            ],
        ]);
    }
}
