import json
import os
import re
import time
from typing import Any, Dict

import requests
from app.bcut_asr.__main__ import run as run_asr
from ui import ConstData, MyUtils


def parse_and_fix_json(json_string):
    """
    解析并修复JSON字符串

    Args:
        json_string: 待解析的JSON字符串

    Returns:
        dict: 解析后的字典，如果解析失败返回None
    """
    if not json_string or not json_string.strip():
        return None

    # 清理字符串
    json_string = json_string.strip()

    # 尝试直接解析
    try:
        return json.loads(json_string)
    except json.JSONDecodeError:
        pass

    # 尝试修复双大括号问题（LLM生成的常见问题）
    try:
        # 将双大括号替换为单大括号
        fixed_braces = json_string.replace('{{', '{').replace('}}', '}')
        return json.loads(fixed_braces)
    except json.JSONDecodeError:
        pass

    # 尝试提取JSON部分
    try:
        # 查找JSON代码块
        json_match = re.search(r'```json\s*(.*?)\s*```', json_string, re.DOTALL)
        if json_match:
            json_content = json_match.group(1).strip()
            return json.loads(json_content)
    except json.JSONDecodeError:
        pass

    # 尝试查找大括号包围的内容
    try:
        # 查找第一个 { 到最后一个 } 的内容
        start_idx = json_string.find('{')
        end_idx = json_string.rfind('}')
        if start_idx != -1 and end_idx != -1 and end_idx > start_idx:
            json_content = json_string[start_idx:end_idx + 1]
            return json.loads(json_content)
    except json.JSONDecodeError:
        pass

    # 尝试综合修复JSON格式问题
    try:
        fixed_json = json_string

        # 1. 修复双大括号问题
        fixed_json = fixed_json.replace('{{', '{').replace('}}', '}')

        # 2. 提取JSON内容（如果有其他文本包围）
        start_idx = fixed_json.find('{')
        end_idx = fixed_json.rfind('}')
        if start_idx != -1 and end_idx != -1 and end_idx > start_idx:
            fixed_json = fixed_json[start_idx:end_idx + 1]

        # 3. 移除注释
        fixed_json = re.sub(r'#.*', '', fixed_json)
        fixed_json = re.sub(r'//.*', '', fixed_json)

        # 4. 移除多余的逗号
        fixed_json = re.sub(r',\s*}', '}', fixed_json)
        fixed_json = re.sub(r',\s*]', ']', fixed_json)

        # 5. 修复单引号
        fixed_json = re.sub(r"'([^']*)':", r'"\1":', fixed_json)

        # 6. 修复没有引号的属性名
        fixed_json = re.sub(r'(\w+)(\s*):', r'"\1"\2:', fixed_json)

        # 7. 修复重复的引号
        fixed_json = re.sub(r'""([^"]*?)""', r'"\1"', fixed_json)

        fixed_json = fixed_json.replace('...', '')

        return json.loads(fixed_json)
    except json.JSONDecodeError:
        pass

    # 如果所有方法都失败，尝试创建一个基本的结构

    # 尝试从文本中提取关键信息创建基本结构
    try:
        # 这是一个简单的回退方案
        return {
            "items": [
                {
                    "_id": 1,
                    "timestamp": "00:00:00,000-00:00:10,000",
                    "picture": "解析失败，使用默认内容",
                    "narration": json_string[:100] + "..." if len(json_string) > 100 else json_string,
                    "OST": 0
                }
            ]
        }
    except Exception:
        return None



def _render_prompt_template(template: str, parameters: Dict[str, Any]) -> str:
    rendered = template
    for key, value in parameters.items():
        text_value = str(value)
        rendered = rendered.replace(f"${{{key}}}", text_value)
        rendered = rendered.replace(f"${key}", text_value)
    return rendered


def _load_script_generation_prompt(parameters: Dict[str, Any]) -> str:
    with open(ConstData.plan_path, "r", encoding="utf-8") as f:
        template = f.read()
    return _render_prompt_template(template, parameters)


def _clean_json_output(output: Any) -> str:
    """清理 JSON 输出，移除 markdown 代码块标记。"""
    text = "" if output is None else str(output)
    text = re.sub(r"^```json\s*", "", text, flags=re.MULTILINE)
    text = re.sub(r"^```\s*$", "", text, flags=re.MULTILINE)
    text = re.sub(r"^```.*$", "", text, flags=re.MULTILINE)
    text = re.sub(r"^```", "", text)
    text = re.sub(r"```$", "", text)
    return text.strip()


def _poll_remote_task(base_interface: str, task_id: str) -> Dict[str, Any]:
    while True:
        if ConstData.cut_stop:
            return {"status": "stop"}

        response = requests.get(
            f"{base_interface}generate-ai-effect/{task_id}",
            timeout=60,
        )
        if response.status_code == 200:
            data = response.json()
            status = data.get("status")
            if status in ("pending", "running"):
                pass
            elif status == "failed":
                return {"status": "failed", "data": data}
            elif status:
                return {"status": "success", "data": data}
        time.sleep(1)


def _submit_remote_task(
    endpoint: str,
    data: Dict[str, Any],
    model_type: int,
    attempts: int,
    retry_delay_seconds: int,
) -> Dict[str, Any]:
    base_interface = ConstData.get_model_interface(model_type)
    for attempt in range(attempts):
        if attempt > 0:
            time.sleep(attempt * retry_delay_seconds)

        response = requests.post(
            f"{base_interface}{endpoint}",
            data=data,
            timeout=600,
        )
        print(f"response.status_code:{response.status_code}")
        if response.status_code != 200:
            continue

        response_data = response.json()
        print(f"response_data:{response_data}")
        if response_data.get("status") != "pending":
            continue

        task_id = response_data.get("taskId")
        if not task_id:
            continue

        result = _poll_remote_task(base_interface, task_id)
        if result["status"] in ("success", "stop"):
            return result

    return {"status": "error", "message": ""}


def _analyze_subtitle_remote(
    subtitle_content: str,
    model: str,
    project_name: str = "",
    model_type: int = 1,
) -> Dict[str, Any]:
    try:
        result = _submit_remote_task(
            endpoint="generate_subtitle_new",
            data={
                "subtitle_content": subtitle_content,
                "model_name": model,
                "model_type": model_type,
                "temperature": 1.0,
                "user_id": ConstData.uid,
                "token": ConstData.token,
                "project_name": project_name,
            },
            model_type=model_type,
            attempts=3,
            retry_delay_seconds=5,
        )
        if result["status"] == "stop":
            return {"status": "stop"}
        if result["status"] == "success":
            data = result["data"]
            return {
                "status": "success",
                "analysis": data.get("text", ""),
                "cacheName": data.get("cacheName", ""),
                "model": model,
                "temperature": 1.0,
            }
    except Exception as e:
        return {"status": "error", "message": str(e), "temperature": 1.0}

    return {"status": "error", "message": "", "temperature": 1.0}


def _generate_narration_script_remote(
    model: str,
    short_name: str,
    plot_analysis: str,
    subtitle_content: str = "",
    temperature: float = 0.7,
    characters_num: str = "",
    original_rate: str = "",
    subtitle_path: str = "",
    auxiliary_words: str = "",
    speech_rate: str = "",
    freeze_frame_ratio: str = "",
    project_name: str = "",
    cache_name: str = "",
    model_type: int = 1,
) -> Dict[str, Any]:
    try:
        prompt = _load_script_generation_prompt(
            {
                "characters_num": characters_num,
                "original_rate": original_rate,
                "drama_name": short_name,
                "plot_analysis": plot_analysis,
                "subtitle_content": "缓存里的字幕" if cache_name is not None else subtitle_content,
                "auxiliary_words": auxiliary_words,
                "speech_rate": speech_rate,
                "freeze_frame_ratio": freeze_frame_ratio,
                "subtitle_time": ConstData.generate_subtitle_time(subtitle_path, characters_num),
            }
        )
        timestamp = time.strftime("%Y-%m%d-%H%M%S")
        with open(f"data/{timestamp}_提示词.txt", "w", encoding="utf-8") as f:
            f.write(prompt)

        result = _submit_remote_task(
            endpoint="generate_script_new",
            data={
                "prompt": prompt,
                "model_name": model,
                "model_type": model_type,
                "temperature": temperature,
                "user_id": ConstData.uid,
                "token": ConstData.token,
                "project_name": project_name,
                "cache_name": cache_name,
            },
            model_type=model_type,
            attempts=4,
            retry_delay_seconds=20,
        )
        if result["status"] == "stop":
            return {"status": "stop"}
        if result["status"] == "success":
            cleaned_result = _clean_json_output(result["data"].get("text", ""))
            with open(f"data/{timestamp}_google.txt", "w", encoding="utf-8") as f:
                f.write(cleaned_result)
            return {
                "status": "success",
                "narration_script": ConstData.resolve_script(cleaned_result),
                "model": model,
                "temperature": temperature,
            }
    except Exception as e:
        return {"status": "error", "message": str(e), "temperature": temperature}

    return {"status": "error", "message": "", "temperature": temperature}


def generate_script_short_sunmmary(video_origin_path, subtitle_path, video_theme, temperature, path: str,
                                   signal: ConstData.WorkerSignals, model_name: str, characters_num: str,
                                   original_rate: str, auxiliary_words: str, speech_rate: str,
                                   project_name: str = "", model_type: int = 1,
                                   freeze_frame_ratio: str = "") -> str:
    """
    生成 短剧解说 视频脚本
    要求: 提供高质量短剧字幕
    适合场景: 短剧
    """
    progress_bar = signal.update_progress
    status_text = signal.update_label
    alarm = signal.alarm

    # success = signal.success

    def update_progress(progress: float, message: str = ""):
        progress_bar.emit(progress)
        if message:
            status_text.emit(f"{progress}% - {message}")
        else:
            status_text.emit(f"进度: {progress}%")
        time.sleep(0.5)

    try:
        if not video_origin_path:
            alarm.emit(1, "未选择视频")
            return ''
        """
        1. 获取字幕
        """
        update_progress(20, "正在分析画面...")
        if subtitle_path == '':
            full_name_os = os.path.basename(video_origin_path)
            subtitle_path = f"{os.path.dirname(video_origin_path)}/{full_name_os.rsplit('.', 1)[-2]}.srt"
            if not os.path.exists(subtitle_path):
                print("生成字幕")
                run_asr(video_origin_path)
        print(f'subtitle_path: {subtitle_path}')
        # 判断字幕文件是否存在
        if not os.path.exists(subtitle_path):
            alarm.emit(1, "字幕文件不存在")
            return ''

        """
        2. 分析字幕总结剧情 - 使用新的LLM服务架构
        """
        # 读取字幕文件内容（无论使用哪种实现都需要）
        with open(subtitle_path, 'r', encoding='utf-8') as f:
            subtitle_content = f.read()
        subtitle_content = MyUtils.compress_srt(subtitle_content)
        try:
            analysis_result = _analyze_subtitle_remote(
                subtitle_content=subtitle_content,
                model=model_name,
                project_name=project_name,
                model_type=model_type,
            )
        except Exception as e:
            alarm.emit(1, "模型返回错误，请重新提交！")
            return ''
        if analysis_result["status"] == 'stop':
            return ''
        """
        3. 根据剧情生成解说文案
        """
        if analysis_result["status"] == "success":
            update_progress(30, f'{model_name}正在计算')

            # 根据剧情生成解说文案 - 使用远程短剧接口
            try:
                narration_result = _generate_narration_script_remote(
                    model=model_name,
                    characters_num=characters_num,
                    original_rate=original_rate,
                    short_name=video_theme,
                    plot_analysis=analysis_result["analysis"],
                    subtitle_content=subtitle_content,
                    temperature=temperature,
                    subtitle_path=subtitle_path,
                    auxiliary_words=auxiliary_words,
                    speech_rate=speech_rate,
                    freeze_frame_ratio=freeze_frame_ratio,
                    project_name=project_name,
                    cache_name=analysis_result.get("cacheName", ""),
                    model_type=model_type,
                )
            except Exception as e:
                alarm.emit(1, "模型返回错误，请重新提交！")
                return ''
            if narration_result["status"] == 'stop':
                return ''
            if narration_result["status"] == "success":
                pass
            else:
                alarm.emit(1, "模型返回错误，请重新提交！")
                return ''
        else:
            alarm.emit(1, "模型返回错误，请重新提交！")
            return ''
        update_progress(40, f'{model_name}正在计算')
        """
        4. 生成文案
        """
        print(f'narration_result:{narration_result}')

        # 结果转换为JSON字符串
        narration_dict = narration_result["narration_script"]
        # 增强JSON解析，包含错误处理和修复
        # narration_dict = parse_and_fix_json(narration_script)
        print(narration_dict)
        print(f"narration_dict type:{type(narration_dict)}")
        # if narration_dict is None:
        #     alarm.emit(1, "生成的解说文案格式错误，无法解析为JSON")

        # 验证JSON结构
        if 'items' not in narration_dict:
            alarm.emit(1, "模型返回错误，请重新提交！")
            return ''

        script = narration_dict['items']

        if script is None:
            alarm.emit(1, "模型返回错误，请重新提交！")
            return ''

        # if isinstance(script, list):
        #     success.emit(json.dumps(script))
        # elif isinstance(script, str):
        #     success.emit(script)
        # update_progress(30, "整理输出脚本...")

        time.sleep(0.1)
        # update_progress(35, "脚本生成完成")
        # progress_bar.emit(100)
        # status_text.emit("脚本生成完成！")
        if isinstance(script, list):
            return json.dumps(script)
        elif isinstance(script, str):
            return script
        # alarm.emit(1, "视频脚本生成成功")

    except Exception as err:
        alarm.emit(1, f"生成过程中发生错误: {str(err)}")
    finally:
        time.sleep(2)
