<?php

namespace App\Modules\Inventory\Services;

use App\Modules\Inventory\Models\Inventory;
use App\Modules\Inventory\Models\InventoryTransferOrder;
use App\Modules\Inventory\Models\InventoryTransferItem;
use App\Modules\Inventory\Models\Warehouse;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class TransferService
{
    /**
     * 建立調撥單草稿
     */
    public function createOrder(int $fromWarehouseId, int $toWarehouseId, ?string $remarks, int $userId): InventoryTransferOrder
    {
        return InventoryTransferOrder::create([
            'from_warehouse_id' => $fromWarehouseId,
            'to_warehouse_id' => $toWarehouseId,
            'status' => 'draft',
            'remarks' => $remarks,
            'created_by' => $userId,
        ]);
    }

    /**
     * 更新調撥單明細
     */
    /**
     * 更新調撥單明細 (支援精確 Diff 與自動日誌整合)
     */
    public function updateItems(InventoryTransferOrder $order, array $itemsData): bool
    {
        return DB::transaction(function () use ($order, $itemsData) {
            // 1. 準備舊資料索引 (Key: product_id . '_' . batch_number)
            $oldItemsMap = $order->items->mapWithKeys(function ($item) {
                $key = $item->product_id . '_' . ($item->batch_number ?? '');
                return [$key => $item];
            });

            $diff = [
                'added' => [],
                'removed' => [],
                'updated' => [],
            ];

            // 2. 處理新資料 (Deleted and Re-inserted currently for simplicity, but logic simulates update)
            // 為了保持 ID 當作外鍵的穩定性，最佳做法是 update 存在的，create 新的，delete 舊的。
            // 但考量現有邏輯是 delete all -> create all，我們維持原策略但優化 Diff 計算。
            
            // 由於採用全刪重建，我們必須手動計算 Diff
            $order->items()->delete();

            $newItemsKeys = [];

            foreach ($itemsData as $data) {
                $key = $data['product_id'] . '_' . ($data['batch_number'] ?? '');
                $newItemsKeys[] = $key;

                $item = $order->items()->create([
                    'product_id' => $data['product_id'],
                    'batch_number' => $data['batch_number'] ?? null,
                    'quantity' => $data['quantity'],
                    'position' => $data['position'] ?? null,
                    'notes' => $data['notes'] ?? null,
                ]);
                // Eager load product for name
                $item->load('product');

                // 比對邏輯
                if ($oldItemsMap->has($key)) {
                    $oldItem = $oldItemsMap->get($key);
                    // 檢查數值是否有變動
                    if ((float)$oldItem->quantity !== (float)$data['quantity'] ||
                        $oldItem->notes !== ($data['notes'] ?? null) ||
                        $oldItem->position !== ($data['position'] ?? null)) {
                        
                        $diff['updated'][] = [
                            'product_name' => $item->product->name,
                            'old' => [
                                'quantity' => (float)$oldItem->quantity,
                                'position' => $oldItem->position,
                                'notes' => $oldItem->notes,
                            ],
                            'new' => [
                                'quantity' => (float)$data['quantity'],
                                'position' => $item->position,
                                'notes' => $item->notes,
                            ]
                        ];
                    }
                } else {
                    // 新增 (使用者需求：顯示為更新，從 0 -> X)
                    $diff['updated'][] = [
                        'product_name' => $item->product->name,
                        'old' => [
                            'quantity' => 0,
                            'notes' => null,
                        ],
                        'new' => [
                            'quantity' => (float)$item->quantity,
                            'notes' => $item->notes,
                        ]
                    ];
                }
            }

            // 3. 處理被移除的項目
            foreach ($oldItemsMap as $key => $oldItem) {
                if (!in_array($key, $newItemsKeys)) {
                    $diff['removed'][] = [
                        'product_name' => $oldItem->product->name,
                        'old' => [
                            'quantity' => (float)$oldItem->quantity,
                            'notes' => $oldItem->notes,
                        ]
                    ];
                }
            }

            // 4. 將 Diff 注入到 Model 的暫存屬性中
            $hasChanged = !empty($diff['added']) || !empty($diff['removed']) || !empty($diff['updated']);
            if ($hasChanged) {
                 $order->activityProperties['items_diff'] = $diff;
            }

            return $hasChanged;
        });
    }

    /**
     * 過帳 (Post) - 執行調撥 (直接扣除來源，增加目的)
     */
    public function post(InventoryTransferOrder $order, int $userId): void
    {
        // [IMPORTANT] 強制重新載入品項，因為在 Controller 中可能剛執行過 updateItems，導致記憶體中快取的 items 是舊的或空的
        $order->load('items.product');

        DB::transaction(function () use ($order, $userId) {
            $fromWarehouse = $order->fromWarehouse;
            $toWarehouse = $order->toWarehouse;

            foreach ($order->items as $item) {
                if ($item->quantity <= 0) continue;

                // 1. 處理來源倉 (扣除)
                $sourceInventory = Inventory::where('warehouse_id', $order->from_warehouse_id)
                    ->where('product_id', $item->product_id)
                    ->where('batch_number', $item->batch_number)
                    ->first();

                if (!$sourceInventory || $sourceInventory->quantity < $item->quantity) {
                    $availableQty = $sourceInventory->quantity ?? 0;
                    $shortageQty = $item->quantity - $availableQty;
                    throw ValidationException::withMessages([
                        'items' => ["商品 {$item->product->name} (批號: {$item->batch_number}) 在來源倉庫存不足。現有庫存：{$availableQty}，尚欠：{$shortageQty}。"],
                    ]);
                }

                $oldSourceQty = $sourceInventory->quantity;
                $newSourceQty = $oldSourceQty - $item->quantity;

                // 儲存庫存快照
                $item->update(['snapshot_quantity' => $oldSourceQty]);
                
                $sourceInventory->quantity = $newSourceQty;
                // 更新總值 (假設成本不變)
                $sourceInventory->total_value = $sourceInventory->quantity * $sourceInventory->unit_cost;
                $sourceInventory->save();

                // 記錄來源交易
                $sourceInventory->transactions()->create([
                    'type' => '調撥出庫',
                    'quantity' => -$item->quantity,
                    'unit_cost' => $sourceInventory->unit_cost,
                    'balance_before' => $oldSourceQty,
                    'balance_after' => $newSourceQty,
                    'reason' => "調撥單 {$order->doc_no} 至 {$toWarehouse->name}",
                    'actual_time' => now(),
                    'user_id' => $userId,
                ]);

                // 2. 處理目的倉 (增加)
                $targetInventory = Inventory::firstOrCreate(
                    [
                        'warehouse_id' => $order->to_warehouse_id,
                        'product_id' => $item->product_id,
                        'batch_number' => $item->batch_number,
                        'location' => $item->position, // 同步貨道至庫存位置
                    ],
                    [
                        'quantity' => 0,
                        'unit_cost' => $sourceInventory->unit_cost, // 繼承成本
                        'total_value' => 0,
                        // 繼承其他屬性
                        'expiry_date' => $sourceInventory->expiry_date,
                        'quality_status' => $sourceInventory->quality_status,
                        'origin_country' => $sourceInventory->origin_country,
                    ]
                );
                
                // 若是新建立的，且成本為0，確保繼承成本
                if ($targetInventory->wasRecentlyCreated && $targetInventory->unit_cost == 0) {
                     $targetInventory->unit_cost = $sourceInventory->unit_cost;
                }

                $oldTargetQty = $targetInventory->quantity;
                $newTargetQty = $oldTargetQty + $item->quantity;

                $targetInventory->quantity = $newTargetQty;
                $targetInventory->total_value = $targetInventory->quantity * $targetInventory->unit_cost;
                $targetInventory->save();

                // 記錄目的交易
                $targetInventory->transactions()->create([
                    'type' => '調撥入庫',
                    'quantity' => $item->quantity,
                    'unit_cost' => $targetInventory->unit_cost,
                    'balance_before' => $oldTargetQty,
                    'balance_after' => $newTargetQty,
                    'reason' => "調撥單 {$order->doc_no} 來自 {$fromWarehouse->name}",
                    'actual_time' => now(),
                    'user_id' => $userId,
                ]);
            }

            // 準備品項快照供日誌使用
            $itemsSnapshot = $order->items->map(function($item) {
                return [
                    'product_name' => $item->product->name,
                    'old' => [
                        'quantity' => (float)$item->quantity,
                        'notes' => $item->notes,
                    ],
                    'new' => [
                        'quantity' => (float)$item->quantity,
                        'notes' => $item->notes,
                    ]
                ];
            })->toArray();

            $order->status = 'completed';
            $order->posted_at = now();
            $order->posted_by = $userId;
            $order->save(); // 觸發自動日誌
        });
    }

    public function void(InventoryTransferOrder $order, int $userId): void
    {
        if ($order->status !== 'draft') {
             throw new \Exception('只能作廢草稿狀態的單據');
        }
        $order->update([
             'status' => 'voided',
             'updated_by' => $userId
        ]);
    }
}
