<?php

namespace addons\shopro\job;

use addons\shopro\library\HttpClient as Http;
use addons\shopro\service\user\Ai;
use app\admin\model\shopro\AiTryon as AiTryOnModel;
use think\queue\Job;
use think\facade\Notification as NotificationFacade;

/**
 * AI生成视频查询状态任务
 */
class AiVideoRetry extends BaseJob
{

    // 火山引擎方舟配置
    private $ark_host = 'https://ark.cn-beijing.volces.com';

    // 调试日志 && 自定义日志
    private function debug_log($text='', $user_id = 0){
//        debug_echo($text);
        custom_log($text, $user_id, 'gen_ai');
    }

    // 最大重试次数
    const MAX_RETRY = 300;

    // 重试延迟时间（秒）- 放入队尾时的延迟
    const RETRY_DELAY = 1;

    /**
     * AI视频结果处理
     */
    public function exec(Job $job, $data)
    {
        try {

            // 获取重试次数（首次执行时为0）
            $retryCount = isset($data['retry_count']) ? (int)$data['retry_count'] : 0;

            $taskid = $data['taskId'];
            $id = $data['id'];
            $user = $data['user'];
            $user_id = isset($user['id']) ? $user['id'] : 0;

            $this->debug_log(' =='.date('Y-m-d H:i:s'). ' ['.$id.'][AI视频查询异步队列]查询AI视频状态脚本开始 userid '.$user_id.' taskid:'.$taskid.' id:'.$id.'=='.PHP_EOL , $user_id);

            // 校验入参
            if (empty($id) || empty($user_id) || empty($taskid)) {

                $this->debug_log('['.$id.'][AI视频查询异步队列]入参有空值 tryon_id:'.$id .' user_id:'.$user_id.' taskid:'.$taskid , $user_id);

                // 删除队列job
                $this->debug_log('['.$id.'][AI视频查询异步队列]删除Job', $user_id);
                $job->delete();
                return false;
            }

            // 1. 根据任务ID, 请求AI接口，查询视频状态
            $url = $this->ark_host . '/api/v3/contents/generations/tasks/' . $taskid;
            $params = [
                'headers' => [
                    'Authorization' => 'Bearer ' . config('shopro.ai_api_key'),
                    'Content-Type'  => 'application/json'
                ],
                'verify'          => false,  // 关闭 SSL 证书验证
                'allow_redirects' => true
            ];

            $this->debug_log('['.$id.'][AI视频查询异步队列]请求AI接口入参 user_id:'.$user_id.' AI接口url:'.$url.' params:'.json_encode($params), $user_id);

            // 向AI接口 发送请求
            $client = new Http();
            $response = $client->get($url, $params);
            $content = $response->getBody()->getContents();
            $content = trim($content);
            $content = preg_replace('/[^\x20-\x7E]/', '', $content);
            $result = json_decode($content, true);

            $this->debug_log('['.$id.'][AI视频查询异步队列]请求AI接口出参 response:'.json_encode($result), $user_id);

            // 2. AI接口 返回值处理 接口失败场景
            if (isset($result['error'])){
                $message = $result['error']['message'] ?? '未知错误';
                AiTryOnModel::where('user_id', $user_id)
                    ->where('ai_task_id', $taskid)
                    ->where('id', $id)
                    ->update(['ai_status' => 2, 'ai_err_msg' => $message]);

                // 删除队列job
                $this->debug_log('['.$id.'][AI视频查询异步队列]删除Job', $user_id);
                $job->delete();
                return false;
            }

            // 3. AI接口 返回值处理 接口成功场景
            if (isset($result['status'])){
                switch ($result['status']) {
                    case 'succeeded':
                        // 任务成功

                        // 保存远程视频到本地
                        $aiService = new Ai();
                        $video_url = $aiService->saveFileObs(isset($result['content']['video_url']) ? $result['content']['video_url'] : '', '.mp4', 'gen_ai', $user_id);

                        $this->debug_log('['.$id.'][AI视频查询异步队列]保存本地接口返回值 video_url:'.$video_url, $user_id);

                        if ($video_url === 0){
                            AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频保存到本地失败']);
                            $this->debug_log('['.$id.'][AI视频查询异步队列]保存本地视频失败 sql: '.db()->getLastSql(), $user_id);
                        }

                        // 更新我的试戴记录
                        AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 1,'ai_url' => $video_url, 'ai_err_msg' => '视频已完成']);
                        $this->debug_log('['.$id.'][AI视频查询异步队列]保存本地视频成功 sql: '.db()->getLastSql(), $user_id);

                        // 发送成功消息通知
                        $aiService->sendNotification($user_id, $id);

                        // 删除队列job
                        $this->debug_log('['.$id.'][AI视频查询异步队列]删除Job', $user_id);
                        $job->delete();

                        break;

                    case 'cancelled':
                    case 'failed':
                    case 'expired':
                        // 任务已过期

                        $msg = [
                            'cancelled' => '任务已取消',
                            'failed' => '视频生成失败',
                            'expired' => '任务已过期'
                        ][$result['status']];

                        AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => $msg]);
                        $this->debug_log('['.$id.'][AI视频查询异步队列]AI视频任务 过期: taskId: ' . $taskid . 'userId '. $user_id, $user_id);
                        $this->debug_log('['.$id.'][AI视频查询异步队列]AI视频任务 过期: result:'.json_encode($result), $user_id);
                        $this->debug_log('['.$id.'][AI视频查询异步队列]AI视频任务 过期: sql:' .db()->getLastSql(), $user_id);

                        // 删除队列job
                        $this->debug_log('['.$id.'][AI视频查询异步队列]删除Job', $user_id);
                        $job->delete();

                        break;

                    // 排队中 / 运行中
                    case 'queued':
                    case 'running':
                        AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_err_msg' => '视频生成中']);

                        // 放入队尾，继续等待
                        $this->releaseJob($job, $data, $retryCount);

                        break;
                }
            }

        } catch (\Exception $e) {

            AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频生成异常']);
            $this->debug_log('['.$id.'][AI视频异步队列]异常: taskId: ' . $taskid . 'userId '. $user_id, $user_id);
            $this->debug_log('['.$id.'][AI视频异步队列]异常: sql:' .db()->getLastSql(), $user_id);

            // 队列执行失败
            format_log_error_custom_name($e, '[AI视频异步队列] user_id:'.$user_id, '', 'gen_ai');

            // 删除队列job
            $this->debug_log('['.$id.'][AI视频异步队列]删除Job', $user_id);
            $job->delete();

        }
    }

    // 重试逻辑
    private function releaseJob(Job $job, &$data, $retryCount)
    {

        $taskid = $data['taskId'];
        $id = $data['id'];
        $user = $data['user'];
        $user_id = isset($user['id']) ? $user['id'] : 0;

        if ($retryCount < self::MAX_RETRY) {
            // 重试次数未达到上限，放入队尾继续重试
            $retryCount++;
            $data['retry_count'] = $retryCount; // 存储到data中

            // release(0) 立即放入队尾，release($delay) 延迟后放入队尾
            $this->debug_log('['.$id.'][AI视频查询异步队列]放入队尾Job: taskId:  ' . $taskid . ' userId: '. $user_id . ' retryCount: ' . $retryCount. 'id: ' . $id, $user_id);
            $job->release(self::RETRY_DELAY);

        } else {
            // 重试次数已达上限，标记失败
            AiTryOnModel::where('user_id', $user_id)->where('ai_task_id', $taskid)->update(['ai_status' => 2, 'ai_err_msg' => '视频生成超时']);
            $this->debug_log('['.$id.'][AI视频查询异步队列]超时未得到结果: taskId: ' . $taskid . 'userId '. $user_id . ' retryCount: ' . $retryCount. 'id: ' . $id, $user_id);
            $this->debug_log('['.$id.'][AI视频查询异步队列][删除Job]超时未得到结果: sql:' .db()->getLastSql(), $user_id);

            // 删除队列job
            $job->delete();
        }
    }

}