<?php

namespace App\Http\Controllers\Api\V1\App;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Machine\Machine;
use App\Models\System\User;
use App\Jobs\Machine\ProcessHeartbeat;
use App\Jobs\Machine\ProcessTimerStatus;
use App\Jobs\Machine\ProcessCoinInventory;
use App\Jobs\Machine\ProcessMachineError;
use App\Jobs\Machine\ProcessStateLog;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Cache;

class MachineController extends Controller
{
    /**
     * B010: Machine Heartbeat & Status Update (Asynchronous)
     */
    public function heartbeat(Request $request)
    {
        $machine = $request->get('machine');
        $data = $request->except(['machine', 'key']); // 排除 Middleware 注入的 Model 物件與認證 key

        // === 狀態異動觸發 (Redis 快取免查 DB) ===
        $cacheKey = "machine:{$machine->serial_no}:state";
        $oldState = Cache::get($cacheKey);

        $currentPage = $data['current_page'] ?? null;
        $doorStatus = $data['door_status'] ?? null;
        $firmwareVersion = $data['firmware_version'] ?? null;
        $model = $data['model'] ?? null;

        if ($currentPage !== null || $doorStatus !== null || $firmwareVersion !== null || $model !== null) {
            // 更新目前狀態到 Redis (保存 1 天)
            $newState = $oldState ?? [];
            if ($currentPage !== null) $newState['current_page'] = $currentPage;
            if ($doorStatus !== null) $newState['door_status'] = $doorStatus;
            if ($firmwareVersion !== null) $newState['firmware_version'] = $firmwareVersion;
            if ($model !== null) $newState['model'] = $model;

            Cache::put($cacheKey, $newState, 86400);

            // 若有歷史紀錄才進行比對 (避開 Cache Miss 造成的雪崩)
            if ($oldState !== null) {
                // 1. 判斷頁面是否變更
                if ($currentPage !== null && (string)$currentPage !== (string)($oldState['current_page'] ?? '')) {
                    // 只記錄「絕對狀態」，配合 lang 中 "Page X" 的翻譯
                    ProcessStateLog::dispatch($machine->id, $machine->company_id, "Page {$currentPage}", 'info');
                }

                // 2. 判斷門禁是否變更 (0: 關閉, 1: 開啟)
                if ($doorStatus !== null && (string)$doorStatus !== (string)($oldState['door_status'] ?? '')) {
                    $doorMessage = $doorStatus == 1 ? "Door Opened" : "Door Closed";
                    $doorLevel = 'info'; // 不論開關門皆為 info，避免觸發異常狀態
                    ProcessStateLog::dispatch($machine->id, $machine->company_id, $doorMessage, $doorLevel);
                }

                // 3. 判斷韌體版本是否變更
                if ($firmwareVersion !== null && (string)$firmwareVersion !== (string)($oldState['firmware_version'] ?? '')) {
                    $oldVersion = $oldState['firmware_version'] ?? 'Unknown';
                    // 直接在 Controller 進行翻譯並填值，確保儲存到 DB 的是最終正確字串
                    $versionMessage = __("Firmware updated to :version", ['version' => $firmwareVersion]);
                    ProcessStateLog::dispatch(
                        $machine->id, 
                        $machine->company_id, 
                        $versionMessage, 
                        'info',
                        ['old' => $oldVersion, 'new' => $firmwareVersion]
                    );
                }

                // 4. 判斷型號是否變更
                if ($model !== null && (string)$model !== (string)($oldState['model'] ?? '')) {
                    $oldModel = $oldState['model'] ?? 'Unknown';
                    $modelMessage = __("Model changed to :model", ['model' => $model]);
                    ProcessStateLog::dispatch(
                        $machine->id, 
                        $machine->company_id, 
                        $modelMessage, 
                        'info',
                        ['old' => $oldModel, 'new' => $model]
                    );
                }
            }
        }

        // 異步處理狀態更新
        ProcessHeartbeat::dispatch($machine->serial_no, $data);

        // 取出待處理指令
        $command = \App\Models\Machine\RemoteCommand::where('machine_id', $machine->id)
            ->pending()
            ->first();

        $status = '49'; // 預設 49 (OK / No Command)
        $message = 'OK';

        if ($command) {
            switch ($command->command_type) {
                case 'reboot':
                    $status = '51';
                    $message = 'reboot';
                    break;
                case 'reboot_card':
                    $status = '60';
                    $message = 'reboot card machine';
                    break;
                case 'checkout':
                    $status = '61';
                    $message = 'checkout';
                    break;
                case 'lock':
                    $status = '71';
                    $message = 'lock';
                    break;
                case 'unlock':
                    $status = '70';
                    $message = 'unlock';
                    break;
                case 'change':
                    $status = '82';
                    $message = $command->payload['amount'] ?? '0';
                    break;
                case 'dispense':
                    $status = '85';
                    $message = $command->payload['slot_no'] ?? '';
                    break;
                case 'reload_stock':
                    $status = '49';
                    $message = 'reload B017';
                    break;
            }
            // 標記為已發送 (sent)
            $command->update(['status' => 'sent', 'executed_at' => now()]);
        }

        return response()->json([
            'success' => true,
            'code' => 200,
            'message' => $message,
            'status' => $status
        ], 202); // 202 Accepted
    }

    /**
     * B018: Record Machine Restock/Setup Report (Asynchronous)
     */
    public function recordRestock(Request $request)
    {
        $machine = $request->get('machine');
        $data = $request->except(['machine', 'key']); // 排除 Middleware 注入物件
        $data['serial_no'] = $machine->serial_no;

        \App\Jobs\Machine\ProcessRestockReport::dispatch($data);

        return response()->json([
            'success' => true,
            'code' => 200,
            'message' => 'Restock report accepted',
            'status' => '49'
        ], 202);
    }

    /**
     * B017: Get Slot Info & Stock (Synchronous)
     */
    /**
     * B017: Get Slot Info & Stock (Synchronous - Full Sync)
     */
    public function getSlots(Request $request)
    {
        $machine = $request->get('machine');
        
        // 依貨道編號排序 (Sorted by slot_no as requested)
        $slots = $machine->slots()->with('product')->orderBy('slot_no')->get();

        // 自動轉 Success: 若機台來撈 B017，代表之前的 reload_stock 指令已成功被機台響應
        // 同時處理 sent 與 pending 狀態，確保狀態機正確關閉
        \App\Models\Machine\RemoteCommand::where('machine_id', $machine->id)
            ->where('command_type', 'reload_stock')
            ->whereIn('status', ['pending', 'sent'])
            ->update([
                'status' => 'success', 
                'executed_at' => now(),
                'note' => __('Inventory synced with machine')
            ]);

        return response()->json([
            'success' => true,
            'code' => 200,
            'data' => $slots->map(function ($slot) {
                return [
                    'tid' => $slot->slot_no,
                    'num' => (int)$slot->stock,
                    'expiry_date' => $slot->expiry_date ? $slot->expiry_date->format('Y-m-d') : null,
                    'batch_no' => $slot->batch_no,
                    // 保留原始欄位以供除錯或未來擴充
                    'product_id' => $slot->product_id,
                    'capacity' => $slot->max_stock, 
                    'status' => $slot->is_active ? '1' : '0',
                ];
            })
        ]);
    }


    /**
     * B710: Sync Timer status (Asynchronous)
     */
    public function syncTimer(Request $request)
    {
        $machine = $request->get('machine');
        $data = $request->except(['machine', 'key']); // 排除 Middleware 注入物件

        ProcessTimerStatus::dispatch($machine->serial_no, $data);

        return response()->json(['success' => true], 202);
    }

    /**
     * B220: Sync Coin Inventory (Asynchronous)
     */
    public function syncCoinInventory(Request $request)
    {
        $machine = $request->get('machine');
        $data = $request->except(['machine', 'key']); // 排除 Middleware 注入物件

        ProcessCoinInventory::dispatch($machine->serial_no, $data);

        return response()->json(['success' => true], 202);
    }

    /**
     * B650: Verify Member Code/Barcode (Synchronous)
     */
    public function verifyMember(Request $request)
    {
        $validator = Validator::make($request->all(), [
            'code' => 'required|string',
        ]);

        if ($validator->fails()) {
            return response()->json(['success' => false, 'message' => 'Invalid code'], 400);
        }

        $code = $request->input('code');

        // 搜尋會員 (barcode 或特定驗證碼)
        $member = \App\Models\Member\Member::where('barcode', $code)
            ->orWhere('id', $code) // 暫時支援 ID
            ->first();

        if (!$member) {
            return response()->json([
                'success' => false,
                'code' => 404,
                'message' => 'Member not found'
            ], 404);
        }

        return response()->json([
            'success' => true,
            'code' => 200,
            'data' => [
                'member_id' => $member->id,
                'name' => $member->name,
                'points' => $member->points,
                'wallet_balance' => $member->wallet_balance ?? 0,
            ]
        ]);
    }

    /**
     * B005: Download Machine Advertisements (Synchronous)
     */
    public function getAdvertisements(Request $request)
    {
        $machine = $request->get('machine');

        $advertisements = \App\Models\Machine\MachineAdvertisement::where('machine_id', $machine->id)
            ->with([
                'advertisement' => function ($query) {
                    $query->playing();
                }
            ])
            ->get()
            ->filter(fn($ma) => $ma->advertisement !== null)
            ->map(function ($ma) {
                // 定義顯示順序權重 (待機 > 購物 > 成功禮)
                $posWeight = [
                    'standby' => 1,
                    'vending' => 2,
                    'visit_gift' => 3
                ];

                // 為了相容現有機台 App 邏輯：
                // App 讀取 t070v03 作為位置標籤 (flag)：
                // 1. HomeActivity (待機) 讀取 "3"
                // 2. FontendActivity (販賣頁) 讀取 "1"
                $posIdMap = [
                    'standby' => '3',
                    'vending' => '1',
                    'visit_gift' => '2'
                ];

                return [
                    't070v01' => $ma->advertisement->name,
                    't070v02' => (string) ($ma->advertisement->duration ?? 15), // 秒數改放這裡
                    't070v03' => (string) ($posIdMap[$ma->position] ?? '1'),    // 位置數字改放這裡 (App 會讀這欄當 Flag)
                    't070v04' => $ma->advertisement->url ? (str_starts_with($ma->advertisement->url, 'http') ? $ma->advertisement->url : asset($ma->advertisement->url)) : '',
                    't070v05' => (string) $ma->sort_order,
                    'raw_pos_weight' => $posWeight[$ma->position] ?? 99,
                    'raw_sort' => (int) $ma->sort_order
                ];
            })
            ->sortBy([
                ['raw_pos_weight', 'asc'],
                ['raw_sort', 'asc']
            ])
            ->values()
            ->map(function ($item) {
                unset($item['raw_pos_weight'], $item['raw_sort']);
                return $item;
            });

        return response()->json([
            'success' => true,
            'code' => 200,
            'data' => $advertisements->values()
        ]);
    }

    /**
     * B009: Report Machine Slot List / Supplementary (Synchronous)
     */
    public function reportSlotList(Request $request, \App\Services\Machine\MachineService $machineService)
    {
        $machine = $request->get('machine');
        $payload = $request->all();
        $account = $payload['account'] ?? null;

        // 1. 驗證帳號是否存在 (驗證執行補貨的人員身分)
        $user = User::where('username', $account)
            ->orWhere('email', $account)
            ->first();

        if (!$user) {
            return response()->json([
                'success' => false,
                'code' => 403,
                'message' => 'Unauthorized: Account not found',
                'status' => ''
            ], 403);
        }

        // 2. 階層式權限驗證 (遵循 RBAC 多租戶規範)
        $isAuthorized = false;
        if ($user->isSystemAdmin()) {
            // [系統層]：系統管理員可異動所有機台
            $isAuthorized = true;
        } elseif ($user->is_admin) {
            // [公司層]：公司管理員需驗證此機台是否隸屬於該公司
            $isAuthorized = ($machine->company_id === $user->company_id);
        } else {
            // [人員層]：一般人員需檢查 machine_user 授權表
            $isAuthorized = $user->machines()->where('machine_id', $machine->id)->exists();
        }

        if (!$isAuthorized) {
            return response()->json([
                'success' => false,
                'code' => 403,
                'message' => 'Unauthorized: Account not authorized for this machine',
                'status' => ''
            ], 403);
        }

        // 3. 映射舊版機台回傳格式 (Map legacy machine format)
        // 支持單個物件 data: {} 或 陣列 data: [{}] (Handle both single object and array)
        $legacyData = $payload['data'] ?? [];
        if (Arr::isAssoc($legacyData)) {
            $legacyData = [$legacyData];
        }

        $mappedSlots = array_map(function ($item) {
            return [
                'slot_no' => $item['tid'] ?? null,
                'product_id' => $item['t060v00'] ?? null,
                'stock' => $item['num'] ?? 0,
                'type' => $item['type'] ?? null,
            ];
        }, $legacyData);

        // 過濾無效資料 (Filter invalid entries)
        $mappedSlots = array_filter($mappedSlots, fn($s) => $s['slot_no'] !== null);

        // 同步處理更新庫存 (直接更新不進隊列)
        $machineService->syncSlots($machine, $mappedSlots);

        return response()->json([
            'success' => true,
            'code' => 200,
            'message' => 'Slot report synchronized success',
            'status' => '49'
        ]);
    }

    /**
     * B012_new: Download Product Catalog (Synchronous)
     */
    public function getProducts(Request $request)
    {
        $machine = $request->get('machine');

        $products = \App\Models\Product\Product::where('company_id', $machine->company_id)
            ->with(['translations'])
            ->active()
            ->get()
            ->map(function ($product) {
                // 提取多語系名稱 (Extract translations)
                $nameEn = $product->translations->firstWhere('locale', 'en')?->value ?? '';
                $nameJp = $product->translations->firstWhere('locale', 'ja')?->value ?? '';

                return [
                    't060v00' => (string) $product->id, // ID 仍建議維持字串，增加未來編號彈性
                    't060v01' => $product->name,
                    't060v01_en' => $nameEn,
                    't060v01_jp' => $nameJp,
                    't060v03' => $product->spec ?? '',
                    't060v06' => $product->image_url ? (str_starts_with($product->image_url, 'http') ? $product->image_url : asset($product->image_url)) : '',
                    't060v09' => (float) $product->price,
                    't060v11' => (int) ($product->track_limit ?? 10),
                    't060v30' => (float) ($product->member_price ?? $product->price),
                    't060v40' => $product->metadata['marketing_plan'] ?? '', // 行銷計畫
                    't060v41' => $product->metadata['material_code'] ?? $product->barcode ?? '', // 物料編碼 (優先從 metadata 找，回退至條碼)
                    'spring_limit' => (int) ($product->spring_limit ?? 10),
                    'track_limit' => (int) ($product->track_limit ?? 10),
                    't063v03' => (float) $product->price,
                ];
            });

        return response()->json([
            'success' => true,
            'code' => 200,
            'data' => $products
        ]);
    }

    /**
     * B013: Report Machine Hardware Error/Status (Asynchronous)
     */
    public function reportError(Request $request)
    {
        $machine = $request->get('machine');
        $data = $request->only(['tid', 'error_code']);

        // 異步分派處理 (Dispatch to queue)
        ProcessMachineError::dispatch($machine->serial_no, $data);

        return response()->json([
            'success' => true,
            'code' => 200,
            'message' => 'Error report accepted',
        ], 202); // 202 Accepted
    }

    /**
     * B014: Download Machine Settings & Config (Synchronous, Requires User Auth)
     * 用於機台引導階段，同步金流、發票與機台專屬 API Token。
     */
    public function getSettings(Request $request)
    {
        $serialNo = $request->input('machine');
        $user = $request->user();

        // 1. 查找機台 (忽略全局範圍以進行認領)
        $machine = Machine::withoutGlobalScopes()
            ->with(['paymentConfig', 'company'])
            ->where('serial_no', $serialNo)
            ->first();

        if (!$machine) {
            return response()->json([
                'success' => false,
                'code' => 404,
                'message' => 'Machine not found'
            ], 404);
        }

        // 2. 權限加強驗證 (RBAC)
        $isAuthorized = false;
        if ($user->isSystemAdmin()) {
            $isAuthorized = true;
        } elseif ($machine->company_id === $user->company_id) {
            // 公司管理員或已授權員工才能存取
            if ($user->is_admin || $user->machines()->where('machine_id', $machine->id)->exists()) {
                $isAuthorized = true;
            }
        }

        if (!$isAuthorized) {
            return response()->json([
                'success' => false,
                'code' => 403,
                'message' => 'Forbidden: You do not have permission to configure this machine'
            ], 403);
        }

        // 3. 獲取關聯設定
        $paymentSettings = $machine->paymentConfig->settings ?? [];
        $companySettings = $machine->company->settings ?? [];

        // 4. 映射 App 預期欄位 (嚴格遵守 HttpAPI.java 結構)
        $data = [
            't050v01' => $machine->serial_no,
            'api_token' => $machine->api_token, // 向 App 核發正式通訊 Token
            
            // 玉山支付
            't050v41' => $paymentSettings['esun_store_id'] ?? '',
            't050v42' => $paymentSettings['esun_term_id'] ?? '',
            't050v43' => $paymentSettings['esun_hash'] ?? '',

            // 電子發票 (綠界)
            't050v34' => $companySettings['invoice_merchant_id'] ?? '',
            't050v35' => $companySettings['invoice_hash_key'] ?? '',
            't050v36' => $companySettings['invoice_hash_iv'] ?? '',
            't050v38' => $companySettings['invoice_email'] ?? '',

            // 趨勢支付 (TrendPay/Greenpay)
            'TP_APP_ID' => $paymentSettings['tp_app_id'] ?? '',
            'TP_APP_KEY' => $paymentSettings['tp_app_key'] ?? '',
            'TP_PARTNER_KEY' => $paymentSettings['tp_partner_key'] ?? '',
            
            // 各類行動支付特店 ID
            'TP_LINE_MERCHANT_ID' => $paymentSettings['tp_line_merchant_id'] ?? '',
            'TP_PS_MERCHANT_ID' => $paymentSettings['tp_ps_merchant_id'] ?? '',
            'TP_EASY_MERCHANT_ID' => $paymentSettings['tp_easy_merchant_id'] ?? '',
            'TP_PI_MERCHANT_ID' => $paymentSettings['tp_pi_merchant_id'] ?? '',
            'TP_JKO_MERCHANT_ID' => $paymentSettings['tp_jko_merchant_id'] ?? '',
        ];

        return response()->json([
            'success' => true,
            'code' => 200,
            'data' => [$data] // App 預期的是包含單一物件的陣列
        ]);
    }
}
