<?php

namespace App\Livewire\Inventory;

use App\Domain\Inventory\Models\Kit;
use App\Domain\Inventory\Models\Warehouse;
use App\Domain\Inventory\Services\KitService;
use App\Domain\Shared\Exceptions\DomainException;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Livewire\Concerns\AppliesRoleScope;
use App\Livewire\Concerns\WithSorting;
use Illuminate\Validation\Rule;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

#[Layout('layouts.app')]
#[Title('الأطقم')]
class KitList extends Component
{
    use WithPagination, AppliesRoleScope, WithSorting, UsesBranchScope;

    protected string $scopePermission = 'inventory.manage';

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

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

    public bool $showAssembleModal = false;
    public bool $showDisassembleModal = false;
    public ?int $selectedKitId = null;
    public ?int $selectedWarehouseId = null;
    public int $assemblyQuantity = 1;

    public function mount(): void
    {
        $this->authorize('inventory.manage');
    }

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

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

    public function toggleActive(int $kitId): void
    {
        $kit = Kit::findOrFail($kitId);
        $kit->update(['is_active' => !$kit->is_active]);
    }

    public function openAssembleModal(int $kitId): void
    {
        $this->selectedKitId = $kitId;
        $this->assemblyQuantity = 1;
        $this->selectedWarehouseId = null;
        $this->showAssembleModal = true;
    }

    public function openDisassembleModal(int $kitId): void
    {
        $this->selectedKitId = $kitId;
        $this->assemblyQuantity = 1;
        $this->selectedWarehouseId = null;
        $this->showDisassembleModal = true;
    }

    /**
     * A warehouse the current branch is allowed to move stock in.
     *
     * exists: is a raw table query — the branch scope on Warehouse never
     * reaches it — and $selectedWarehouseId is a plain public property, so
     * without this the modal would accept any warehouse id in the academy and
     * KitService would consume and produce stock in another branch's store.
     */
    private function warehouseRule(): \Illuminate\Validation\Rules\Exists
    {
        $branchId = $this->getActiveBranchId();

        return Rule::exists('warehouses', 'id')
            ->where('academy_id', app('current_academy')->id)
            ->whereNull('deleted_at')
            ->when($branchId !== null, fn ($rule) => $rule->where(
                fn ($q) => $q->where('branch_id', $branchId)
            ));
    }

    public function assemble(KitService $kitService): void
    {
        $this->validate([
            'selectedWarehouseId' => ['required', $this->warehouseRule()],
            'assemblyQuantity' => 'required|integer|min:1',
        ], [
            'selectedWarehouseId.required' => 'يجب اختيار المستودع',
            'assemblyQuantity.required' => 'الكمية مطلوبة',
            'assemblyQuantity.min' => 'الكمية يجب أن تكون 1 على الأقل',
        ]);

        try {
            $kit = Kit::findOrFail($this->selectedKitId);
            $warehouse = Warehouse::findOrFail($this->selectedWarehouseId);

            $kitService->assemble($kit, $warehouse, $this->assemblyQuantity, auth()->user());

            $this->showAssembleModal = false;
            session()->flash('success', __('تم تجميع الطقم بنجاح'));
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
            $this->showAssembleModal = false;
        }
    }

    public function disassemble(KitService $kitService): void
    {
        $this->validate([
            'selectedWarehouseId' => ['required', $this->warehouseRule()],
            'assemblyQuantity' => 'required|integer|min:1',
        ], [
            'selectedWarehouseId.required' => 'يجب اختيار المستودع',
            'assemblyQuantity.required' => 'الكمية مطلوبة',
            'assemblyQuantity.min' => 'الكمية يجب أن تكون 1 على الأقل',
        ]);

        try {
            $kit = Kit::findOrFail($this->selectedKitId);
            $warehouse = Warehouse::findOrFail($this->selectedWarehouseId);

            $kitService->disassemble($kit, $warehouse, $this->assemblyQuantity, auth()->user());

            $this->showDisassembleModal = false;
            session()->flash('success', __('تم تفكيك الطقم بنجاح'));
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
            $this->showDisassembleModal = false;
        }
    }

    public function render()
    {
        $branchId = $this->getActiveBranchId();
        $query = Kit::query()
            ->when($branchId, fn ($q) => $q->whereHas('components.product', fn ($p) => $p->where(fn ($b) => $b->whereNull('branch_id')->orWhere('branch_id', $branchId))))
            ->withCount('components')
            ->when($this->search, function ($q) {
                $search = $this->search;
                $q->where(function ($q2) use ($search) {
                    $q2->where('name_ar', 'ilike', "%{$search}%")
                       ->orWhere('name', 'ilike', "%{$search}%")
                       ->orWhere('sku', 'ilike', "%{$search}%");
                });
            })
            ->when($this->activeFilter !== '', function ($q) {
                if ($this->activeFilter === '1') {
                    $q->where('is_active', true);
                } elseif ($this->activeFilter === '0') {
                    $q->where('is_active', false);
                }
            })
            ->orderBy($this->sortBy, $this->sortDir);

        $this->applyRoleScope($query);

        return view('livewire.inventory.kit-list', [
            'kits' => $query->paginate(20),
            // Branch comes from Warehouse's own scope. active() is the fix that
            // was missing: the assemble/disassemble modals were offering retired
            // warehouses as somewhere to move stock.
            'warehouses' => Warehouse::active()->orderBy('name_ar')->get(['id', 'name_ar']),
        ]);
    }
}
