<?php

namespace App\Jobs\Machine;

use App\Models\Machine\Machine;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class ProcessHeartbeat implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $serialNo;
    protected $payload;

    /**
     * Create a new job instance.
     */
    public function __construct(string $serialNo, $payload)
    {
        $this->serialNo = $serialNo;
        $this->payload = (array) $payload;
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        $machine = Machine::withoutGlobalScopes()->where('serial_no', $this->serialNo)->first();

        if (!$machine) {
            Log::warning("MQTT Heartbeat: Machine not found", ['serial_no' => $this->serialNo]);
            return;
        }

        // 更新機台狀態
        Log::debug("ProcessHeartbeat: Attempting to set status to online for {$this->serialNo}");
        $updateData = [
            'last_heartbeat_at' => now(),
            'status' => 'online',
        ];

        // === 狀態異動觸發 (Redis 快取，讓 MQTT 也支援日誌) ===
        $cacheKey = "machine:{$this->serialNo}:state";
        $oldState = \Illuminate\Support\Facades\Cache::get($cacheKey);
        // 1. 偵測狀態由離線轉在線 (寫入日誌)
        if ($machine->status === 'offline') {
            \App\Jobs\Machine\ProcessStateLog::dispatch(
                $machine->id,
                $machine->company_id,
                "Machine is online",
                'info',
                []
            );
        }

        $newState = $oldState ?? [];

        // 2. 韌體版本比對 (有改才傳，有改才記)
        if (isset($this->payload['firmware_version'])) {
            $fv = (string) $this->payload['firmware_version'];
            if (!isset($oldState['firmware_version']) || (string)$oldState['firmware_version'] !== $fv) {
                \App\Jobs\Machine\ProcessStateLog::dispatch(
                    $machine->id,
                    $machine->company_id,
                    "Firmware updated to :version",
                    'info',
                    ['version' => $fv, 'old' => $oldState['firmware_version'] ?? 'Unknown']
                );
            }
            $updateData['firmware_version'] = $fv;
            $newState['firmware_version'] = $fv;
        }

        // 2. 溫度更新 (只要有變動就紀錄日誌)
        if (isset($this->payload['temperature'])) {
            $temp = (int) $this->payload['temperature'];
            Log::debug("ProcessHeartbeat: Temperature reported for {$this->serialNo}: {$temp}");
            $updateData['temperature'] = $temp;

            // 讀取最後一次記錄日誌的溫度與時間
            $tempLogCacheKey = "machine:{$this->serialNo}:last_temp_log";
            $lastLogEntry = \Illuminate\Support\Facades\Cache::get($tempLogCacheKey);

            $shouldLog = false;
            if (!$lastLogEntry) {
                $shouldLog = true;
            } else {
                $lastValue = (int) $lastLogEntry['value'];
                $lastAt = \Carbon\Carbon::parse($lastLogEntry['at']);

                // 條件 A: 只要溫度與上次記錄不同就記錄 (整數比對)
                if ($temp !== $lastValue) {
                    Log::debug("ProcessHeartbeat: Temperature changed from {$lastValue} to {$temp}. Triggering log.");
                    $shouldLog = true;
                }
                // 條件 B: 距離上次日誌超過 4 小時 (保底機制)
                if ($lastAt->diffInHours(now()) >= 4) {
                    $shouldLog = true;
                }
            }

            if ($shouldLog) {
                \App\Jobs\Machine\ProcessStateLog::dispatch(
                    $machine->id,
                    $machine->company_id,
                    "Temperature reported: :temp°C",
                    'info',
                    ['temp' => $temp]
                );

                // 更新快取，保留 7 天
                \Illuminate\Support\Facades\Cache::put($tempLogCacheKey, [
                    'value' => $temp,
                    'at' => now()->toDateTimeString()
                ], 604800);
            }
        }

        // 更新快取
        \Illuminate\Support\Facades\Cache::put($cacheKey, $newState, 86400);

        $machine->update($updateData);
    }
}
