<?php

namespace App\Livewire\Inventory;

use App\Domain\Inventory\Models\InventoryLevel;
use App\Domain\Inventory\Models\Product;
use App\Domain\Inventory\Models\Warehouse;
use App\Domain\Shared\Traits\UsesBranchScope;
use App\Livewire\Concerns\WithSorting;
use Illuminate\Support\Facades\DB;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

#[Layout('layouts.app')]
#[Title('حركة المخزون')]
class MovementList extends Component
{
    use WithPagination, UsesBranchScope, WithSorting;

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

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

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

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

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

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

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

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

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

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

    public function updatedDirection(): void
    {
        $this->movementType = '';
        $this->resetPage();
    }

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

    public function render()
    {
        $branchId = $this->getActiveBranchId();
        $academyId = app('current_academy')?->id ?? auth()->user()->academy_id;

        // Raw builder: the movement list joins three tables for their display
        // columns, and DB::table() sees neither the academy scope nor the branch
        // scope. Every predicate below therefore has to be written by hand, on
        // every joined table — filtering only the driving one would still print
        // another branch's product and warehouse names into the rows.
        //
        // A raw join sees no global scope, so every joined table is filtered
        // by hand — the movements, and the products and warehouses they name.
        $query = DB::table('inventory_movements')
            ->join('products', 'inventory_movements.product_id', '=', 'products.id')
            ->join('warehouses', 'inventory_movements.warehouse_id', '=', 'warehouses.id')
            // The academy predicate for the creator goes in the ON clause, not
            // the WHERE: in the WHERE it would silently turn this left join into
            // an inner one and drop every movement with no recorded creator.
            ->leftJoin('users', fn ($join) => $join
                ->on('inventory_movements.created_by', '=', 'users.id')
                ->where('users.academy_id', '=', $academyId))
            ->where('inventory_movements.academy_id', $academyId)
            ->where('products.academy_id', $academyId)
            ->where('warehouses.academy_id', $academyId)
            ->when($branchId, fn ($q) => $q
                ->where('inventory_movements.branch_id', $branchId)
                ->where(fn ($p) => $p->where('products.branch_id', $branchId)->orWhereNull('products.branch_id'))
                ->where(fn ($w) => $w->where('warehouses.branch_id', $branchId)->orWhereNull('warehouses.branch_id')))
            ->select([
                'inventory_movements.*',
                'products.name_ar as product_name_ar',
                'products.sku as product_sku',
                'warehouses.name_ar as warehouse_name_ar',
                'users.name_ar as creator_name_ar',
                'users.name as creator_name',
            ])
            ->when($this->search, function ($q) {
                $search = $this->search;
                $q->where(function ($q2) use ($search) {
                    $q2->where('products.name_ar', 'ilike', "%{$search}%")
                       ->orWhere('products.sku', 'ilike', "%{$search}%");
                });
            })
            ->when($this->dateFrom, fn ($q) => $q->where('inventory_movements.created_at', '>=', $this->dateFrom . ' 00:00:00'))
            ->when($this->dateTo, fn ($q) => $q->where('inventory_movements.created_at', '<=', $this->dateTo . ' 23:59:59'))
            ->when($this->movementType, fn ($q) => $q->where('inventory_movements.movement_type', $this->movementType))
            ->when($this->direction, fn ($q) => $q->where('inventory_movements.direction', $this->direction))
            ->when($this->warehouseFilter, fn ($q) => $q->where('inventory_movements.warehouse_id', $this->warehouseFilter))
            ->orderBy('inventory_movements.' . $this->sortBy, $this->sortDir);

        $allTypes = [
            'purchase_received' => 'استلام مشتريات',
            'sale' => 'بيع',
            'transfer_out' => 'تحويل صادر',
            'transfer_in' => 'تحويل وارد',
            'return_to_stock' => 'مرتجع للمخزون',
            'return_to_supplier' => 'مرتجع للمورد',
            'adjustment_up' => 'تسوية بالزيادة',
            'adjustment_down' => 'تسوية بالنقص',
            'damage' => 'تلف',
            'loss' => 'فقد',
            'consumption' => 'استهلاك',
            'kit_assembly' => 'تجميع طقم',
            'kit_disassembly' => 'تفكيك طقم',
            'initial_stock' => 'رصيد افتتاحي',
            'count_adjustment_up' => 'تسوية جرد بالزيادة',
            'count_adjustment_down' => 'تسوية جرد بالنقص',
        ];

        $inTypes = ['purchase_received', 'transfer_in', 'return_to_stock', 'adjustment_up', 'kit_disassembly', 'initial_stock', 'count_adjustment_up'];
        $outTypes = ['sale', 'transfer_out', 'return_to_supplier', 'adjustment_down', 'damage', 'loss', 'consumption', 'kit_assembly', 'count_adjustment_down'];

        $movementTypeOptions = match ($this->direction) {
            'in' => array_intersect_key($allTypes, array_flip($inTypes)),
            'out' => array_intersect_key($allTypes, array_flip($outTypes)),
            default => $allTypes,
        };

        return view('livewire.inventory.movement-list', [
            'movements' => $query->paginate(25),
            'warehouses' => Warehouse::active()->orderBy('name_ar')->get(['id', 'name_ar']),
            'movementTypeOptions' => $movementTypeOptions,
        ]);
    }
}
