"""
Video 任务处理器
================

管理 Vidu 视频生成任务的提交与轮询。
采用提交 + 轮询两阶段设计。
"""

import logging
from typing import Any

from app.core.platform_config import get_platform_config_loader
from app.scheduler.handlers.base import AsyncHandler
from app.scheduler.models import StateChange
from app.scheduler.registry import TaskRegistry
from app.scheduler.slot_manager import SlotManager
from app.services.vidu_service import ViduService

logger = logging.getLogger(__name__)

SLOT_KEY = "vidu:video_slots"


def _get_video_max_slots() -> int:
    """从 platform-config.yaml 读取 rate_limit 配置作为 max_slots"""
    try:
        loader = get_platform_config_loader()
        platform = loader.get_platform("vidu")
        if platform and "lip_sync" in platform.methods:
            return int(platform.methods["lip_sync"].rate_limit_qps)
        if platform:
            return int(platform.rate_limit_qps)
    except Exception as e:
        logger.warning(f"读取视频平台 rate_limit 配置失败: {e}")
    return 5


class VideoHandler(AsyncHandler):
    name = "video"
    slot_key = SLOT_KEY
    max_slots = _get_video_max_slots()

    def __init__(self, service: ViduService | None = None):
        self.service = service

    def _get_service(self) -> ViduService:
        if self.service is None:
            raise RuntimeError(
                "VideoHandler 需要通过构造函数传入 ViduService 实例"
            )
        return self.service

    async def tick(
        self, tasks: list[Any], registry: TaskRegistry, slots: SlotManager
    ) -> list[StateChange]:
        changes: list[StateChange] = []

        for task in tasks:
            params = task.params or {}
            vidu_task_id = params.get("vidu_task_id")

            if vidu_task_id:
                # 轮询阶段：优先检查 callback 结果，fallback 主动查询 Vidu API
                result_data = task.result or {}
                if result_data.get("video_url") or result_data.get("state") == "success":
                    # callback 已到达，结果已写入 TaskRegistry
                    await registry.remove_running(task.task_id)

                    changes.append(
                        StateChange(
                            task_id=task.task_id,
                            field_path="status",
                            value="completed",
                        )
                    )
                    changes.append(
                        StateChange(
                            task_id=task.task_id,
                            field_path="message",
                            value="视频生成完成",
                        )
                    )
                    changes.append(
                        StateChange(
                            task_id=task.task_id,
                            field_path="completed",
                            value=1,
                        )
                    )
                    changes.append(
                        StateChange(
                            task_id=task.task_id, field_path="total", value=1
                        )
                    )
                elif task.status == "failed":
                    # callback 已标记失败，移除 running
                    await registry.remove_running(task.task_id)
                else:
                    # callback 尚未到达，fallback：主动查询 Vidu API
                    try:
                        service = self._get_service()
                        vidu_status = await service.lip_sync_query(task.task_id)
                        vidu_state = vidu_status.get("state", "")
                        creations = vidu_status.get("creations", [])
                        video_url = creations[0].get("url") if creations else None

                        if vidu_state == "success" and video_url:
                            changes.append(
                                StateChange(
                                    task_id=task.task_id,
                                    field_path="status",
                                    value="completed",
                                )
                            )
                            changes.append(
                                StateChange(
                                    task_id=task.task_id,
                                    field_path="message",
                                    value="视频生成完成",
                                )
                            )
                            changes.append(
                                StateChange(
                                    task_id=task.task_id,
                                    field_path="completed",
                                    value=1,
                                )
                            )
                            changes.append(
                                StateChange(
                                    task_id=task.task_id,
                                    field_path="total",
                                    value=1,
                                )
                            )
                            changes.append(
                                StateChange(
                                    task_id=task.task_id,
                                    field_path="result",
                                    value={
                                        "video_url": video_url,
                                        "state": "success",
                                    },
                                )
                            )
                            # 移除 running set
                            await registry.remove_running(task.task_id)
                            logger.info(
                                f"[Video {task.task_id}] 主动查询 Vidu 任务已完成: "
                                f"video_url={video_url[:60]}..."
                            )
                        elif vidu_state == "failed":
                            changes.append(
                                StateChange(
                                    task_id=task.task_id,
                                    field_path="status",
                                    value="failed",
                                )
                            )
                            changes.append(
                                StateChange(
                                    task_id=task.task_id,
                                    field_path="message",
                                    value="视频生成失败",
                                )
                            )
                            changes.append(
                                StateChange(
                                    task_id=task.task_id,
                                    field_path="error",
                                    value=vidu_status.get("message") or "视频生成失败",
                                )
                            )
                            await registry.remove_running(task.task_id)
                            logger.warning(
                                f"[Video {task.task_id}] 主动查询 Vidu 任务失败: "
                                f"{vidu_status.get('message')}"
                            )
                        else:
                            # 仍在处理中，继续等待
                            logger.debug(
                                f"[Video {task.task_id}] 主动查询 Vidu 状态: {vidu_state}，继续等待"
                            )
                    except Exception as e:
                        logger.warning(
                            f"[Video {task.task_id}] 主动查询 Vidu 失败: {e}"
                        )
                continue  # ← 已提交，不再重复提交

            # 提交阶段：占用 slot，提交成功后自动释放
            async with slots.acquire_ctx(
                SLOT_KEY, task.task_id, self.max_slots
            ) as acquired:
                if not acquired:
                    continue

                try:
                    service = self._get_service()

                    # 自动构建回调地址（前端未传时兜底）
                    callback_url = params.get("callback_url")
                    if not callback_url:
                        from app.config import get_settings

                        base_url = get_settings().app_base_url
                        if base_url:
                            callback_url = f"{base_url}/api/v1/vidu/callback"
                        else:
                            raise ValueError("callback_url 未配置且无法自动推断应用地址")

                    logger.info(
                        f"[Video {task.task_id}] 准备提交 Vidu 视频生成: "
                        f"callback_url={callback_url}, video_url={params.get('video_url', '')[:60]}..."
                    )
                    vidu_task_id = await service.lip_sync_create(
                        video_url=params.get("video_url", ""),
                        audio_url=params.get("audio_url"),
                        text=params.get("text"),
                        voice_id=params.get("voice_id"),
                        speed=float(params.get("speed", 1.0)),
                        volume=int(params.get("volume", 0)),
                        ref_photo_url=params.get("ref_photo_url"),
                        callback_url=callback_url,
                        task_id=task.task_id,
                    )
                    if not vidu_task_id:
                        raise ValueError("未返回任务ID")
                    params["vidu_task_id"] = vidu_task_id
                    changes.append(
                        StateChange(
                            task_id=task.task_id, field_path="params", value=params
                        )
                    )
                    changes.append(
                        StateChange(
                            task_id=task.task_id,
                            field_path="message",
                            value="视频生成任务已提交",
                        )
                    )
                except RuntimeError:
                    logger.error(f"[Video {task.task_id}] service not initialized")
                    changes.append(
                        StateChange(
                            task_id=task.task_id, field_path="status", value="failed"
                        )
                    )
                    changes.append(
                        StateChange(
                            task_id=task.task_id,
                            field_path="message",
                            value="视频处理服务未就绪",
                        )
                    )
                    changes.append(
                        StateChange(
                            task_id=task.task_id,
                            field_path="error",
                            value="视频处理服务未就绪",
                        )
                    )
                except Exception as e:
                    logger.error(f"[Video {task.task_id}] submit error: {e}")
                    changes.append(
                        StateChange(
                            task_id=task.task_id, field_path="status", value="failed"
                        )
                    )
                    changes.append(
                        StateChange(
                            task_id=task.task_id,
                            field_path="message",
                            value="视频生成任务提交失败，请稍后重试",
                        )
                    )
                    changes.append(
                        StateChange(
                            task_id=task.task_id,
                            field_path="error",
                            value="视频生成任务提交失败",
                        )
                    )

        return changes
