<?php

namespace App\Livewire\Inventory;

use App\Domain\Inventory\Models\InventoryLevel;
use App\Domain\Inventory\Models\Product;
use App\Domain\Inventory\Models\StockCount;
use App\Domain\Inventory\Models\Warehouse;
use App\Domain\Inventory\Services\StockCountService;
use App\Domain\Shared\Exceptions\DomainException;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;
use Livewire\Component;

#[Layout('layouts.app')]
#[Title('جرد مخزني جديد')]
class StockCountForm extends Component
{
    public ?int $warehouse_id = null;
    public ?int $stockCountId = null;
    public string $notes = '';

    /** @var array<int, array{product_id: int, name_ar: string, sku: string, system_quantity: int, counted_quantity: ?int}> */
    public array $items = [];

    public function mount(?StockCount $stockCount = null): void
    {
        $this->authorize('inventory.manage');

        if ($stockCount && $stockCount->exists) {
            $this->stockCountId = $stockCount->id;
            $this->warehouse_id = $stockCount->warehouse_id;
            $this->notes = $stockCount->notes ?? '';
            $this->loadExistingItems($stockCount);
        }
    }

    public function rules(): array
    {
        return [
            'warehouse_id' => 'required|exists:warehouses,id',
            'items' => 'required|array|min:1',
            'items.*.counted_quantity' => 'nullable|integer|min:0',
            'notes' => 'nullable|string|max:1000',
        ];
    }

    public function messages(): array
    {
        return [
            'warehouse_id.required' => 'يجب اختيار المستودع',
            'warehouse_id.exists' => 'المستودع غير موجود',
            'items.required' => 'يجب وجود منتجات للجرد',
            'items.min' => 'يجب وجود منتج واحد على الأقل',
            'items.*.counted_quantity.integer' => 'الكمية يجب أن تكون عددًا صحيحًا',
            'items.*.counted_quantity.min' => 'الكمية لا يمكن أن تكون سالبة',
            'notes.max' => 'الملاحظات يجب ألا تتجاوز 1000 حرف',
        ];
    }

    public function updatedWarehouseId(): void
    {
        if ($this->stockCountId) {
            return; // Don't reload if editing existing count
        }

        $this->items = [];

        if (!$this->warehouse_id) {
            return;
        }

        $this->loadWarehouseProducts();
    }

    private function loadWarehouseProducts(): void
    {
        $levels = InventoryLevel::where('warehouse_id', $this->warehouse_id)
            ->with('product:id,name_ar,sku,cost_price')
            ->get();

        $this->items = $levels->map(fn ($level) => [
            'product_id' => $level->product_id,
            'name_ar' => $level->product->name_ar ?? '',
            'sku' => $level->product->sku ?? '',
            'cost_price' => $level->product->cost_price ?? 0,
            'system_quantity' => $level->quantity_on_hand,
            'counted_quantity' => null,
        ])->toArray();
    }

    private function loadExistingItems(StockCount $stockCount): void
    {
        $stockCount->load('items.product:id,name_ar,sku,cost_price');

        $this->items = $stockCount->items->map(fn ($item) => [
            'item_id' => $item->id,
            'product_id' => $item->product_id,
            'name_ar' => $item->product->name_ar ?? '',
            'sku' => $item->product->sku ?? '',
            'cost_price' => $item->product->cost_price ?? 0,
            'system_quantity' => $item->system_quantity,
            'counted_quantity' => $item->counted_quantity,
        ])->toArray();
    }

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

        try {
            $service = app(StockCountService::class);
            $user = auth()->user();

            if ($this->stockCountId) {
                // Continue existing count — record counts for items
                $stockCount = StockCount::findOrFail($this->stockCountId);

                foreach ($this->items as $item) {
                    if ($item['counted_quantity'] === null || $item['counted_quantity'] === '') {
                        continue;
                    }

                    $countItem = $stockCount->items()
                        ->where('id', $item['item_id'] ?? 0)
                        ->orWhere(function ($q) use ($item, $stockCount) {
                            $q->where('stock_count_id', $stockCount->id)
                              ->where('product_id', $item['product_id']);
                        })
                        ->first();

                    if ($countItem) {
                        $service->recordCount($countItem, (int) $item['counted_quantity'], $user);
                    }
                }

                if ($this->notes) {
                    $stockCount->update(['notes' => $this->notes]);
                }

                session()->flash('success', __('تم تحديث بيانات الجرد بنجاح'));
                $this->redirect(route('inventory.stock-counts'), navigate: true);
            } else {
                // Create new stock count
                $productIds = collect($this->items)->pluck('product_id')->toArray();
                $stockCount = $service->create($this->warehouse_id, $productIds, $user);

                if ($this->notes) {
                    $stockCount->update(['notes' => $this->notes]);
                }

                // Record any counts already entered
                foreach ($this->items as $index => $item) {
                    if ($item['counted_quantity'] === null || $item['counted_quantity'] === '') {
                        continue;
                    }

                    $countItem = $stockCount->items()->where('product_id', $item['product_id'])->first();
                    if ($countItem) {
                        $service->recordCount($countItem, (int) $item['counted_quantity'], $user);
                    }
                }

                session()->flash('success', __('تم إنشاء جلسة الجرد بنجاح'));
                $this->redirect(route('inventory.stock-counts'), navigate: true);
            }
        } catch (DomainException $e) {
            session()->flash('error', $e->getMessage());
        } catch (\Exception $e) {
            session()->flash('error', __('حدث خطأ أثناء حفظ الجرد'));
        }
    }

    public function render()
    {
        return view('livewire.inventory.stock-count-form', [
            'warehouses' => Warehouse::active()->orderBy('name_ar')->get(['id', 'name_ar', 'code']),
        ]);
    }
}
