<?php

namespace App\Modules\Inventory\Services;

use App\Modules\Inventory\Models\GoodsReceipt;
use App\Modules\Inventory\Models\GoodsReceiptItem;
use App\Modules\Inventory\Contracts\InventoryServiceInterface;
use App\Modules\Procurement\Contracts\ProcurementServiceInterface;
use Illuminate\Support\Facades\DB;

class GoodsReceiptService
{
    protected $inventoryService;
    protected $procurementService;

    public function __construct(
        InventoryServiceInterface $inventoryService,
        ProcurementServiceInterface $procurementService
    ) {
        $this->inventoryService = $inventoryService;
        $this->procurementService = $procurementService;
    }

    /**
     * Store a new Goods Receipt and process inventory.
     *
     * @param array $data
     * @return GoodsReceipt
     * @throws \Exception
     */
    public function store(array $data)
    {
        return DB::transaction(function () use ($data) {
            // 1. Generate Code
            $data['code'] = $this->generateCode($data['received_date']);
            $data['user_id'] = auth()->id();
            $data['status'] = 'completed'; // Direct completion for now

            // 2. Create Header
            $goodsReceipt = GoodsReceipt::create($data);

            // 3. Process Items
            foreach ($data['items'] as $itemData) {
                // Create GR Item
                $grItem = new GoodsReceiptItem([
                    'product_id' => $itemData['product_id'],
                    'purchase_order_item_id' => $itemData['purchase_order_item_id'] ?? null,
                    'quantity_received' => $itemData['quantity_received'],
                    'unit_price' => $itemData['unit_price'],
                    'total_amount' => $itemData['quantity_received'] * $itemData['unit_price'],
                    'batch_number' => $itemData['batch_number'] ?? null,
                    'expiry_date' => $itemData['expiry_date'] ?? null,
                ]);
                $goodsReceipt->items()->save($grItem);

                // 4. Update Inventory
                $reason = match($goodsReceipt->type) {
                    'standard' => '採購進貨',
                    'miscellaneous' => '雜項入庫',
                    'other' => '其他入庫',
                    default => '進貨入庫',
                };

                $this->inventoryService->createInventoryRecord([
                    'warehouse_id' => $goodsReceipt->warehouse_id,
                    'product_id' => $grItem->product_id,
                    'quantity' => $grItem->quantity_received,
                    'unit_cost' => $grItem->unit_price,
                    'batch_number' => $grItem->batch_number,
                    'expiry_date' => $grItem->expiry_date,
                    'reason' => $reason,
                    'reference_type' => GoodsReceipt::class,
                    'reference_id' => $goodsReceipt->id,
                    'source_purchase_order_id' => $goodsReceipt->purchase_order_id,
                    'arrival_date' => $goodsReceipt->received_date,
                ]);

                // 5. Update PO if linked and type is standard
                if ($goodsReceipt->type === 'standard' && $goodsReceipt->purchase_order_id && $grItem->purchase_order_item_id) {
                    $this->procurementService->updateReceivedQuantity(
                        $grItem->purchase_order_item_id,
                        $grItem->quantity_received
                    );
                }
            }

            return $goodsReceipt;
        });
    }

    private function generateCode(string $date)
    {
        // Format: GR-YYYYMMDD-NN
        $prefix = 'GR-' . date('Ymd', strtotime($date)) . '-';
        
        $last = GoodsReceipt::where('code', 'like', $prefix . '%')
            ->orderBy('id', 'desc')
            ->lockForUpdate()
            ->first();

        if ($last) {
            $seq = intval(substr($last->code, -2)) + 1;
        } else {
            $seq = 1;
        }

        return $prefix . str_pad($seq, 2, '0', STR_PAD_LEFT);
    }
}
