<?php

namespace App\Livewire\Inventory;

use App\Models\Location;
use App\Models\Product;
use App\Models\ProductStock;
use App\Models\Setting;
use App\Models\StockAdjustment;
use App\Models\InventoryAdjustmentBatch;
use App\Services\FifoService;
use Illuminate\Support\Facades\DB;
use Livewire\Component;
use Livewire\WithPagination;
use App\Exports\GenericExport;
use Maatwebsite\Excel\Facades\Excel;

class StockAdjustments extends Component
{
    use WithPagination;
    use \Livewire\WithFileUploads;

    protected $paginationTheme = 'bootstrap';

    public string $search = '';
    public string $typeFilter = '';
    public string $dateFrom = '';
    public string $dateTo = '';
    public int $perPage = 20;

    // Bulk Adjustment Form
    public bool $showBulkModal = false;
    public string $batchReason = '';
    public string $batchNotes = '';
    public string $productSearch = '';
    public array $adjustmentItems = []; // [{product_id, name, sku, system_qty, real_qty}]
    public string $password = '';
    public bool $requiresPassword = false;
    public ?int $adjustmentLocationId = null;
    
    // Import
    public $importFile;

    // Print view
    public ?int $viewBatchId = null;

    public function openBulkModal()
    {
        $this->reset(['batchReason', 'batchNotes', 'productSearch', 'adjustmentItems', 'password', 'adjustmentLocationId']);
        $this->batchReason = 'stocktake';

        $setting = DB::table('settings')
            ->where('key', 'inventory_adjustment_password')
            ->where('value', '!=', '')
            ->first();

        $this->requiresPassword = !empty($setting?->value);

        // Default to first location in user's branch
        $branchId = auth()->user()->branch_id ?? 1;
        $defaultLoc = Location::where('branch_id', $branchId)->where('is_default', true)->first()
                   ?? Location::where('branch_id', $branchId)->active()->first();
        $this->adjustmentLocationId = $defaultLoc?->id;

        $this->showBulkModal = true;
    }

    public function getProductsProperty()
    {
        if (strlen($this->productSearch) < 2) return [];

        $existingIds = collect($this->adjustmentItems)->pluck('product_id')->toArray();

        return Product::query()
            ->active()
            ->whereNotIn('id', $existingIds)
            ->where(function ($q) {
                $q->where('name', 'like', '%' . $this->productSearch . '%')
                  ->orWhere('name_ar', 'like', '%' . $this->productSearch . '%')
                  ->orWhere('sku', 'like', '%' . $this->productSearch . '%')
                  ->orWhere('barcode', 'like', '%' . $this->productSearch . '%');
            })
            ->take(10)
            ->get();
    }

    public function updatedAdjustmentLocationId()
    {
        // Refresh system quantities for already-added items when location changes
        $branchId = auth()->user()->branch_id ?? 1;
        foreach ($this->adjustmentItems as &$item) {
            $stock = ProductStock::where('product_id', $item['product_id'])
                ->where('branch_id', $branchId)
                ->where('location_id', $this->adjustmentLocationId)
                ->first();
            $item['system_qty'] = $stock?->quantity ?? 0;
            $item['real_qty'] = $item['system_qty'];
        }
    }

    public function addProductToAdjustment(int $productId)
    {
        $product = Product::find($productId);
        if (!$product) return;

        $branchId = auth()->user()->branch_id ?? 1;
        $stock = ProductStock::where('product_id', $productId)
            ->where('branch_id', $branchId)
            ->where('location_id', $this->adjustmentLocationId)
            ->first();
        $systemQty = $stock?->quantity ?? 0;

        $this->adjustmentItems[] = [
            'product_id' => $product->id,
            'name' => $product->localized_name,
            'sku' => $product->sku,
            'system_qty' => $systemQty,
            'real_qty' => $systemQty, // default to system qty
        ];

        $this->productSearch = '';
    }

    public function removeItem(int $index)
    {
        unset($this->adjustmentItems[$index]);
        $this->adjustmentItems = array_values($this->adjustmentItems);
    }

    public function submitBulkAdjustment()
    {
        $this->validate([
            'batchReason' => 'required|string|max:255',
            'adjustmentItems' => 'required|array|min:1',
            'adjustmentItems.*.real_qty' => 'required|numeric|min:0',
        ]);

        // Password check
        $setting = DB::table('settings')
            ->where('key', 'inventory_adjustment_password')
            ->where('value', '!=', '')
            ->first();
        $authPassword = $setting?->value;

        if ($authPassword && $this->password !== $authPassword) {
            $this->addError('password', __('Incorrect password.'));
            return;
        }

        $branchId = auth()->user()->branch_id ?? 1;

        try {
            DB::beginTransaction();

            $batch = InventoryAdjustmentBatch::create([
                'batch_number' => InventoryAdjustmentBatch::generateBatchNumber(),
                'branch_id' => $branchId,
                'user_id' => auth()->id(),
                'reason' => $this->batchReason,
                'notes' => $this->batchNotes ?: null,
                'status' => 'submitted',
                'submitted_at' => now(),
            ]);

            foreach ($this->adjustmentItems as $item) {
                $realQty = (float) $item['real_qty'];
                $systemQty = (float) $item['system_qty'];
                $difference = $realQty - $systemQty;

                if (abs($difference) < 0.001) continue; // No change

                // Get or create stock record (location-aware)
                $stock = ProductStock::firstOrCreate(
                    [
                        'product_id' => $item['product_id'],
                        'branch_id' => $branchId,
                        'location_id' => $this->adjustmentLocationId,
                    ],
                    ['quantity' => 0, 'avg_cost' => 0]
                );

                $stockBefore = $stock->quantity;

                // Set stock directly to real quantity
                $stock->update(['quantity' => $realQty]);

                // Record adjustment
                StockAdjustment::create([
                    'batch_id' => $batch->id,
                    'product_id' => $item['product_id'],
                    'branch_id' => $branchId,
                    'location_id' => $this->adjustmentLocationId,
                    'user_id' => auth()->id(),
                    'type' => $difference > 0 ? 'in' : 'out',
                    'quantity' => abs($difference),
                    'reason' => $this->batchReason,
                    'reference' => $batch->batch_number,
                    'stock_before' => $stockBefore,
                    'stock_after' => $realQty,
                ]);

                // FIFO integration
                $product = Product::find($item['product_id']);
                if ($difference > 0) {
                    // Stock IN → create a FIFO lot
                    FifoService::addLot([
                        'product_id'  => $item['product_id'],
                        'branch_id'   => $branchId,
                        'location_id' => $this->adjustmentLocationId,
                        'cost_price'  => $product->cost_price ?? 0,
                        'quantity'    => abs($difference),
                        'source_type' => 'adjustment',
                        'source_id'   => $batch->id,
                    ]);
                } elseif ($difference < 0) {
                    // Stock OUT → consume FIFO lots
                    FifoService::consumeLots(
                        $item['product_id'],
                        $branchId,
                        abs($difference),
                        $this->adjustmentLocationId
                    );
                }
            }

            DB::commit();

            $this->showBulkModal = false;
            $this->viewBatchId = $batch->id;
            session()->flash('success', __('Bulk adjustment submitted successfully. Batch #') . $batch->batch_number);

        } catch (\Exception $e) {
            DB::rollBack();
            session()->flash('error', __('Error recording adjustment: ') . $e->getMessage());
        }
    }

    public function viewBatch(int $id)
    {
        $this->viewBatchId = $id;
    }

    public function closeBatchView()
    {
        $this->viewBatchId = null;
    }

    public function downloadTemplate()
    {
        $rows = [
            ['sku' => 'PROD-001', 'real_qty' => 50],
            ['sku' => 'PROD-002', 'real_qty' => 10],
        ];

        return Excel::download(new GenericExport(
            collect($rows),
            ['SKU', 'Real Quantity'],
            function ($row) {
                return [$row['sku'], $row['real_qty']];
            },
            'Stock_Adjustment_Template'
        ), 'stock_adjustment_template.xlsx');
    }

    public function updatedImportFile()
    {
        $this->validate([
            'importFile' => 'file|mimes:xlsx,xls,csv',
        ]);

        try {
            $rows = Excel::toCollection(new \App\Imports\StockAdjustmentImport, $this->importFile)->first();

            if ($rows->isEmpty()) {
                $this->addError('importFile', __('The file is empty.'));
                return;
            }

            $branchId = auth()->user()->branch_id ?? 1;
            $itemsFound = 0;

            foreach ($rows as $row) {
                if (!isset($row['sku']) || !isset($row['real_qty'])) continue;

                $product = Product::where('sku', $row['sku'])->first();
                if (!$product) continue;

                // Check if already in list
                $exists = false;
                foreach ($this->adjustmentItems as $item) {
                    if ($item['product_id'] === $product->id) {
                        $exists = true;
                        break;
                    }
                }
                if ($exists) continue;

                $stock = ProductStock::where('product_id', $product->id)
                    ->where('branch_id', $branchId)
                    ->where('location_id', $this->adjustmentLocationId)
                    ->first();
                $systemQty = $stock?->quantity ?? 0;

                $this->adjustmentItems[] = [
                    'product_id' => $product->id,
                    'name' => $product->localized_name,
                    'sku' => $product->sku,
                    'system_qty' => $systemQty,
                    'real_qty' => (float) $row['real_qty'],
                ];
                $itemsFound++;
            }

            $this->reset('importFile');
            
            if ($itemsFound > 0) {
                session()->flash('success', __('Imported ' . $itemsFound . ' items.'));
            } else {
                session()->flash('warning', __('No valid new items found in file.'));
            }

        } catch (\Exception $e) {
            $this->addError('importFile', __('Error parsing file: ') . $e->getMessage());
        }
    }

    public function export()
    {
        $batches = InventoryAdjustmentBatch::query()
            ->with(['user', 'branch'])
            ->withCount('items')
            ->when($this->search, function ($q) {
                $q->where('batch_number', 'like', '%' . $this->search . '%')
                  ->orWhere('reason', 'like', '%' . $this->search . '%');
            })
            ->when($this->dateFrom, fn($q) => $q->whereDate('created_at', '>=', $this->dateFrom))
            ->when($this->dateTo, fn($q) => $q->whereDate('created_at', '<=', $this->dateTo))
            ->orderBy('created_at', 'desc')
            ->get();

        return Excel::download(new GenericExport(
            $batches,
            ['Batch Number', 'Date', 'Reason', 'User', 'Branch', 'Items Count'],
            function ($batch) {
                return [
                    $batch->batch_number,
                    $batch->created_at->format('Y-m-d H:i'),
                    $batch->reason,
                    $batch->user?->name ?? 'System',
                    $batch->branch?->name ?? 'Main',
                    $batch->items_count,
                ];
            },
            'Stock_Adjustments_' . now()->format('Y-m-d')
        ), 'stock_adjustments_' . now()->format('YmdHis') . '.xlsx');
    }

    public function exportBatch(int $id)
    {
        $batch = InventoryAdjustmentBatch::with(['user', 'branch', 'items.product', 'items.location'])->findOrFail($id);

        $rows = [];
        foreach ($batch->items as $item) {
            $difference = $item->type === 'in' ? $item->quantity : -$item->quantity;
            
            $rows[] = [
                'date' => $batch->created_at->format('Y-m-d H:i'),
                'batch_number' => $batch->batch_number,
                'user' => $batch->user?->name ?? 'System',
                'branch' => $batch->branch?->name ?? 'Main',
                'reason' => $batch->reason,
                'product' => $item->product?->localized_name ?? '-',
                'sku' => $item->product?->sku ?? '-',
                'type' => ucfirst($item->type),
                'system_qty' => $item->stock_before,
                'real_qty' => $item->stock_after,
                'difference' => $difference,
                'location' => $item->location?->localized_name ?? '-',
            ];
        }

        return Excel::download(new GenericExport(
            collect($rows),
            ['Date', 'Batch Number', 'User', 'Branch', 'Reason', 'Product', 'SKU', 'Type', 'System Qty', 'Real Qty', 'Difference', 'Location'],
            function ($row) {
                return [
                    $row['date'],
                    $row['batch_number'],
                    $row['user'],
                    $row['branch'],
                    $row['reason'],
                    $row['product'],
                    $row['sku'],
                    $row['type'],
                    $row['system_qty'],
                    $row['real_qty'],
                    $row['difference'],
                    $row['location'],
                ];
            },
            'Adjustment_Batch_' . $batch->batch_number
        ), 'adj_batch_' . $batch->batch_number . '.xlsx');
    }

    public function render()
    {
        $batches = InventoryAdjustmentBatch::query()
            ->with(['user', 'items.product'])
            ->when($this->search, function ($q) {
                $q->where('batch_number', 'like', '%' . $this->search . '%')
                  ->orWhere('reason', 'like', '%' . $this->search . '%');
            })
            ->when($this->dateFrom, fn($q) => $q->whereDate('created_at', '>=', $this->dateFrom))
            ->when($this->dateTo, fn($q) => $q->whereDate('created_at', '<=', $this->dateTo))
            ->orderBy('created_at', 'desc')
            ->paginate($this->perPage);

        $viewBatch = null;
        if ($this->viewBatchId) {
            $viewBatch = InventoryAdjustmentBatch::with(['user', 'branch', 'items.product'])->find($this->viewBatchId);
        }

        $branchId = auth()->user()->branch_id ?? 1;
        $locations = Location::where('branch_id', $branchId)->active()->orderBy('sort_order')->get();

        return view('livewire.inventory.adjustments', [
            'batches' => $batches,
            'products' => $this->products,
            'viewBatch' => $viewBatch,
            'currency' => Setting::get('default_currency', 'EGP'),
            'reasons' => \App\Models\InventoryAdjustment::reasons(),
            'locations' => $locations,
        ]);
    }
}
