<?php

namespace App\Jobs;

use App\Models\Terminal;
use App\Models\TerminalSyncLog;
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\Http;
use Illuminate\Support\Facades\Log;

/**
 * 终端配置同步任务
 */
class SyncTerminalConfigJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * 任务最大尝试次数
     *
     * @var int
     */
    public $tries = 3;

    /**
     * 任务超时时间（秒）
     *
     * @var int
     */
    public $timeout = 60;

    /**
     * 创建新的任务实例
     *
     * @param Terminal $terminal
     * @param TerminalSyncLog $log
     */
    public function __construct(
        public Terminal $terminal,
        public TerminalSyncLog $log
    ) {}

    /**
     * 执行任务
     *
     * @return void
     */
    public function handle(): void
    {
        try {
            // 更新状态为同步中
            $this->log->update(['status' => 'syncing']);

            Log::info('开始同步终端配置', [
                'terminal_id' => $this->terminal->id,
                'terminal_name' => $this->terminal->name,
                'log_id' => $this->log->id,
            ]);

            // 模拟同步过程（因为没有真实的终端API）
            // 在实际环境中，这里应该调用真实的终端API
            $this->simulateSync();

            // 更新状态为已同步
            $this->log->update([
                'status' => 'synced',
                'synced_at' => now(),
                'error_message' => null,
            ]);

            Log::info('终端配置同步成功', [
                'terminal_id' => $this->terminal->id,
                'log_id' => $this->log->id,
            ]);

        } catch (\Exception $e) {
            // 记录错误日志
            Log::error('终端配置同步失败', [
                'terminal_id' => $this->terminal->id,
                'log_id' => $this->log->id,
                'error' => $e->getMessage(),
                'attempt' => $this->attempts(),
            ]);

            // 更新状态为失败
            $this->log->update([
                'status' => 'failed',
                'error_message' => $e->getMessage(),
            ]);

            // 如果还有重试次数，则重新抛出异常以触发重试
            if ($this->attempts() < $this->tries) {
                throw $e;
            }
        }
    }

    /**
     * 模拟同步过程
     *
     * @return void
     * @throws \Exception
     */
    private function simulateSync(): void
    {
        // 模拟网络延迟
        sleep(2);

        // 随机模拟成功或失败（90%成功率）
        if (rand(1, 100) <= 10) {
            throw new \Exception('模拟同步失败：网络连接超时');
        }

        // 在实际环境中，这里应该是类似这样的代码：
        // $response = Http::timeout(30)
        //     ->post($this->terminal->sync_url, [
        //         'config' => $this->log->config_snapshot,
        //     ]);
        //
        // if (!$response->successful()) {
        //     throw new \Exception('同步失败：' . $response->body());
        // }
    }

    /**
     * 任务失败时的处理
     *
     * @param \Throwable $exception
     * @return void
     */
    public function failed(\Throwable $exception): void
    {
        Log::error('终端配置同步任务最终失败', [
            'terminal_id' => $this->terminal->id,
            'log_id' => $this->log->id,
            'error' => $exception->getMessage(),
        ]);

        // 确保状态更新为失败
        $this->log->update([
            'status' => 'failed',
            'error_message' => '同步失败（已达最大重试次数）：' . $exception->getMessage(),
        ]);
    }

    /**
     * 计算重试延迟时间（秒）
     *
     * @return int
     */
    public function backoff(): int
    {
        // 指数退避：第1次重试等待10秒，第2次等待30秒
        return [10, 30][$this->attempts() - 1] ?? 60;
    }
}
