<?php

namespace App\Services\Transaction;

use App\Models\Transaction\Order;
use App\Models\Transaction\OrderItem;
use App\Models\Transaction\Invoice;
use App\Models\Transaction\DispenseRecord;
use Illuminate\Support\Facades\DB;
use App\Models\Machine\Machine;
use App\Models\StaffCardLog;
use App\Models\Transaction\PickupCode;
use App\Models\Transaction\PickupCodeLog;
use App\Models\Transaction\PassCodeLog;
use App\Models\Transaction\WelcomeGift;
use App\Models\Transaction\WelcomeGiftLog;
use Illuminate\Support\Facades\Log;
use App\Services\Machine\MachineService;


class TransactionService
{
    protected $machineService;

    public function __construct(MachineService $machineService)
    {
        $this->machineService = $machineService;
    }

    /**
     * Process a new transaction (B600).
     */
    public function processTransaction(array $data): Order
    {
        $flowId = $data['flow_id'] ?? null;

        if ($flowId) {
            $existingOrder = Order::withoutGlobalScopes()
                ->where('flow_id', $flowId)
                ->first();
            if ($existingOrder) {
                return $existingOrder;
            }
        }

        return DB::transaction(function () use ($data) {
            $machine = Machine::where('serial_no', $data['serial_no'])->firstOrFail();

            // Create Order
            $order = Order::create([
                'company_id' => $machine->company_id,
                'flow_id' => $data['flow_id'] ?? null,
                'order_no' => $data['order_no'] ?? $this->generateOrderNo(),
                'machine_id' => $machine->id,
                'member_id' => $data['member_id'] ?? null,
                'total_amount' => $data['total_amount'],
                'discount_amount' => $data['discount_amount'] ?? 0,
                'pay_amount' => $data['pay_amount'],
                'change_amount' => $data['change_amount'] ?? 0,
                'points_used' => $data['points_used'] ?? 0,
                'original_amount' => $data['original_amount'] ?? $data['total_amount'],
                'payment_type' => (int) ($data['payment_type'] ?? 0),
                'payment_status' => $data['payment_status'] ?? 1,
                'payment_request' => $data['payment_request'] ?? null,
                'payment_response' => $data['payment_response'] ?? null,
                'member_barcode' => $data['member_barcode'] ?? null,
                'code_id' => $data['code_id'] ?? null,
                'welcome_gift_id' => $data['welcome_gift_id'] ?? null,
                'invoice_info' => $data['invoice_info'] ?? null,
                'machine_time' => $data['machine_time'] ?? now(),
                'payment_at' => now(),
                'status' => 'completed',
                'metadata' => $data['metadata'] ?? null,
                'delivery_status' => (int) ($data['delivery_status'] ?? Order::DELIVERY_STATUS_SUCCESS),
            ]);

            // Create Order Items
            if (!empty($data['items'])) {
                foreach ($data['items'] as $item) {
                    $productName = $item['product_name'] ?? null;

                    // 如果沒傳名稱，嘗試從資料庫抓取
                    if (empty($productName)) {
                        $product = \App\Models\Product\Product::find($item['product_id']);
                        $productName = $product?->name ?? 'Unknown';
                    }

                    $order->items()->create([
                        'product_id' => $item['product_id'],
                        'product_name' => $productName,
                        'barcode' => $item['barcode'] ?? null,
                        'price' => $item['price'],
                        'quantity' => $item['quantity'],
                        'subtotal' => $item['price'] * $item['quantity'],
                    ]);
                }
            }

            return $order;
        });
    }

    /**
     * Generate a unique order number.
     */
    protected function generateOrderNo(): string
    {
        return 'ORD-' . now()->format('YmdHis') . '-' . strtoupper(bin2hex(random_bytes(3)));
    }

    /**
     * Record Invoice (B601).
     */
    public function recordInvoice(array $data): Invoice
    {
        return DB::transaction(function () use ($data) {
            $machine = Machine::where('serial_no', $data['serial_no'])->firstOrFail();

            $order = null;
            if (!empty($data['flow_id'])) {
                $order = Order::where('flow_id', $data['flow_id'])->first();
            }

            // 處理額外的發票資訊 (business_tax_id, carrier_type)
            $metadata = $data['metadata'] ?? [];
            if (isset($data['business_tax_id']))
                $metadata['business_tax_id'] = $data['business_tax_id'];
            if (isset($data['carrier_type']))
                $metadata['carrier_type'] = $data['carrier_type'];

            return Invoice::create([
                'company_id' => $machine->company_id,
                'order_id' => $order?->id ?? ($data['order_id'] ?? null),
                'machine_id' => $machine->id,
                'flow_id' => $data['flow_id'] ?? null,
                'invoice_no' => $data['invoice_no'] ?? null,
                'amount' => $data['amount'] ?? 0,
                'carrier_id' => $data['carrier_id'] ?? null,
                'invoice_date' => $data['invoice_date'] ?? null,
                'machine_time' => $data['machine_time'] ?? null,
                'random_number' => $data['random_number'] ?? ($data['random_no'] ?? null),
                'love_code' => $data['love_code'] ?? null,
                'rtn_code' => $data['rtn_code'] ?? null,
                'rtn_msg' => $data['rtn_msg'] ?? null,
                'metadata' => $metadata,
            ]);
        });
    }

    /**
     * Record dispense result (B602).
     */
    public function recordDispense(array $data): DispenseRecord
    {
        return DB::transaction(function () use ($data) {
            // Use withoutGlobalScopes for background job safety
            $machine = Machine::withoutGlobalScopes()->where('serial_no', $data['serial_no'])->firstOrFail();

            $order = null;
            if (!empty($data['flow_id'])) {
                $order = Order::withoutGlobalScopes()->where('flow_id', $data['flow_id'])->first();
            }

            // Find slot with robust matching (handle "1" vs "01")
            $slotNo = $data['slot_no'] ?? null;
            $slot = null;
            if ($slotNo) {
                $slot = $machine->slots()->where('slot_no', (string) $slotNo)->first();
                if (!$slot) {
                    $normalized = ltrim((string) $slotNo, '0');
                    if ($normalized === '')
                        $normalized = '0';
                    $slot = $machine->slots()->get()->first(function ($s) use ($normalized) {
                        $sn = ltrim($s->slot_no, '0');
                        if ($sn === '')
                            $sn = '0';
                        return $sn === $normalized;
                    });
                }
            }

            $record = DispenseRecord::create([
                'company_id' => $machine->company_id,
                'order_id' => $order?->id ?? ($data['order_id'] ?? null),
                'flow_id' => $data['flow_id'] ?? null,
                'machine_id' => $machine->id,
                'slot_no' => $slotNo ?? 'unknown',
                'product_id' => ($data['product_id'] ?? 0) > 0 ? $data['product_id'] : ($slot ? $slot->product_id : null),
                'amount' => $data['amount'] ?? 0,
                'remaining_stock' => $data['remaining_stock'] ?? null,
                'dispense_status' => $data['dispense_status'] ?? 0,
                'member_barcode' => $data['member_barcode'] ?? ($order?->member_barcode ?? null),
                'machine_time' => $data['machine_time'] ?? now(),
                'points_used' => $data['points_used'] ?? 0,
            ]);

            // 執行實體庫存扣除 (真實交易化)
            if ((int) ($data['dispense_status'] ?? 0) === 1) {
                if ($slot) {
                    $slot->decrement('stock');

                    $type = \App\Models\Machine\MachineStockMovement::TYPE_SALE;

                    $this->machineService->recordStockMovement(
                        $slot,
                        -1,
                        $type,
                        $order ?? $record,
                        $order ? "Sale Order: #{$order->order_no}" : "Dispense Record: #{$record->id}",
                        ['order_id' => $order?->id, 'dispense_id' => $record->id]
                    );
                } else {
                    // Log warning if slot matching fails to help diagnostic
                    \Log::warning("Dispense record created but slot not found for decrement", [
                        'machine_id' => $machine->id,
                        'slot_no' => $slotNo
                    ]);
                }
            }

            return $record;
        });
    }


    /**
     * Finalize a complete transaction (Unified B600/B601/B602).
     */
    public function finalizeTransaction(array $data): Order
    {
        // 優先從 Root 讀取，再從 order 內讀取
        $flowId = $data['flow_id'] ?? ($data['order']['flow_id'] ?? null);

        // 冪等性檢查：如果 flow_id 已經存在，直接回傳既有訂單
        if ($flowId) {
            $existingOrder = Order::withoutGlobalScopes()->where('flow_id', $flowId)->first();
            if ($existingOrder) {
                Log::info("Transaction already finalized, returning existing order", ['flow_id' => $flowId]);
                return $existingOrder;
            }
        } else {
            throw new \Exception("Flow ID is required for finalization");
        }

        return DB::transaction(function () use ($data, $flowId) {
            $serialNo = $data['serial_no'];

            // 1. Process Order (B600)
            $orderData = $data['order'];
            $orderData['serial_no'] = $serialNo;

            // 確保提取 payment_type 與 flow_id (可能在 root 或 order 內)
            $orderData['flow_id'] = $flowId;
            if (!isset($orderData['delivery_status']) && !empty($data['dispense'])) {
                $orderData['delivery_status'] = $this->resolveDeliveryStatusFromDispense($data['dispense']);
            }
            if (!isset($orderData['payment_type']) && isset($data['payment_type'])) {
                $orderData['payment_type'] = $data['payment_type'];
            }
            $order = $this->processTransaction($orderData);

            // 2. Record Invoice (B601) - Optional
            if (!empty($data['invoice'])) {
                $invoiceData = $data['invoice'];
                $invoiceData['serial_no'] = $serialNo;
                $invoiceData['flow_id'] = $order->flow_id;
                $invoiceData['order_id'] = $order->id;
                $this->recordInvoice($invoiceData);
            }

            // 3. Record Dispense Results (B602) - Optional/Multiple
            if (!empty($data['dispense'])) {
                $dispenseList = isset($data['dispense'][0]) ? $data['dispense'] : [$data['dispense']];
                foreach ($dispenseList as $dispenseItem) {
                    $dispenseItem['serial_no'] = $serialNo;
                    $dispenseItem['flow_id'] = $order->flow_id;
                    $dispenseItem['order_id'] = $order->id;

                    // 自動繼承：如果出貨紀錄沒帶 Barcode，就用訂單的
                    if (empty($dispenseItem['member_barcode']) && !empty($order->member_barcode)) {
                        $dispenseItem['member_barcode'] = $order->member_barcode;
                    }

                    $this->recordDispense($dispenseItem);
                }
            }

            // 4. 閉環勾稽 (Closed Loop Check)
            $codeId = $data['order']['code_id'] ?? ($data['code_id'] ?? null);
            $paymentType = (int) $order->payment_type;

            if ($codeId) {
                switch ($paymentType) {
                    case 41: // 員工卡 (Staff Card)
                        // 建立員工卡核銷日誌
                        StaffCardLog::create([
                            'company_id' => $order->company_id,
                            'machine_id' => $order->machine_id,
                            'staff_card_id' => $codeId,
                            'payment_type' => 41,
                            'code_id' => $codeId,
                            'order_id' => $order->id,
                            'action' => 'consume',
                            'remark' => "MQTT 交易完成自動核銷，訂單: #{$order->id}"
                        ]);
                        break;

                    case 6: // 取貨碼 (Pickup Code)
                        $pickupCode = PickupCode::where('machine_id', $order->machine_id)
                            ->where('id', $codeId)
                            ->where('status', 'active')
                            ->first();
                        if ($pickupCode) {
                            $newCount = $pickupCode->usage_count + 1;
                            $isUsedUp = $newCount >= $pickupCode->usage_limit;

                            $pickupCode->update([
                                'order_id' => $order->id,
                                'usage_count' => $newCount,
                                'status' => $isUsedUp ? 'used' : 'active',
                                'used_at' => $isUsedUp ? now() : $pickupCode->used_at
                            ]);

                            // 建立核銷日誌 (閉環最後一哩路)
                            PickupCodeLog::create([
                                'company_id' => $order->company_id,
                                'machine_id' => $order->machine_id,
                                'pickup_code_id' => $pickupCode->id,
                                'order_id' => $order->id,
                                'action' => $isUsedUp ? 'used' : 'consume',
                                'remark' => "MQTT 交易完成自動核銷 (" . ($newCount) . "/" . $pickupCode->usage_limit . ")，訂單: #{$order->id}",
                                'raw_data' => [
                                    'slot' => $pickupCode->slot_no,
                                    'code' => $pickupCode->code,
                                    'count' => $newCount,
                                    'limit' => $pickupCode->usage_limit
                                ]
                            ]);
                        }
                        break;

                    case 5: // 通行碼 (Pass Code)
                        // 建立通行碼核銷日誌
                        PassCodeLog::create([
                            'company_id' => $order->company_id,
                            'machine_id' => $order->machine_id,
                            'pass_code_id' => $codeId,
                            'order_id' => $order->id,
                            'action' => 'completed',
                            'remark' => "MQTT 交易完成自動紀錄取貨，訂單: #{$order->id}"
                        ]);
                        break;
                }
            }

            // 處理來店禮 (Welcome Gift) 自動核銷
            $welcomeGiftId = $data['order']['welcome_gift_id'] ?? ($data['welcome_gift_id'] ?? null);
            if ($welcomeGiftId) {
                $welcomeGift = WelcomeGift::where('machine_id', $order->machine_id)
                    ->where('id', $welcomeGiftId)
                    ->where('status', 'active')
                    ->first();
                if ($welcomeGift) {
                    $newCount = $welcomeGift->usage_count + 1;
                    $isUsedUp = ($welcomeGift->usage_type === 'once' && $newCount >= ($welcomeGift->usage_limit ?? 1));

                    $welcomeGift->update([
                        'usage_count' => $newCount,
                        'status' => $isUsedUp ? 'used' : 'active',
                    ]);

                    WelcomeGiftLog::create([
                        'company_id' => $order->company_id,
                        'machine_id' => $order->machine_id,
                        'welcome_gift_id' => $welcomeGift->id,
                        'order_id' => $order->id,
                        'action' => 'consume',
                        'remark' => "MQTT 交易完成自動核銷，訂單: #{$order->id}",
                        'raw_data' => [
                            'code' => $welcomeGift->code,
                            'count' => $newCount,
                            'type' => $welcomeGift->usage_type
                        ]
                    ]);
                }
            }


            return $order;
        });
    }

    /**
     * Resolve order-level delivery status from item-level dispense results.
     */
    protected function resolveDeliveryStatusFromDispense(array $dispense): int
    {
        $dispenseList = isset($dispense[0]) ? $dispense : [$dispense];
        $statuses = collect($dispenseList)
            ->filter(fn ($item) => is_array($item) && array_key_exists('dispense_status', $item))
            ->map(fn ($item) => (int) $item['dispense_status']);

        if ($statuses->isEmpty()) {
            return Order::DELIVERY_STATUS_SUCCESS;
        }

        $successCount = $statuses
            ->filter(fn ($status) => $status === Order::DELIVERY_STATUS_SUCCESS)
            ->count();

        if ($successCount === $statuses->count()) {
            return Order::DELIVERY_STATUS_SUCCESS;
        }

        if ($successCount === 0) {
            return Order::DELIVERY_STATUS_FAILED;
        }

        return Order::DELIVERY_STATUS_PARTIAL;
    }
}
