"""
Subtitle 任务处理器
==================

管理火山引擎字幕生成与自动打轴的提交与轮询。
支持两种模式：
- caption: 字幕识别（从音频/视频提取带时间轴的字幕）
- auto_align: 自动打轴（为已有字幕文本配上时间轴）
"""

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.volcengine_caption_service import VolcengineCaptionService

logger = logging.getLogger(__name__)

SLOT_KEY = "volc:subtitle_slots"


def _get_subtitle_max_slots() -> int:
    """从 platform-config.yaml 读取 rate_limit 配置作为 max_slots"""
    try:
        loader = get_platform_config_loader()
        platform = loader.get_platform("volcengine_caption")
        if platform:
            return int(platform.rate_limit_qps)
    except Exception as e:
        logger.warning(f"读取字幕平台 rate_limit 配置失败: {e}")
    return 5


class SubtitleHandler(AsyncHandler):
    name = "subtitle"
    slot_key = SLOT_KEY
    max_slots = _get_subtitle_max_slots()

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

    def _get_service(self) -> VolcengineCaptionService:
        if self.service is None:
            raise RuntimeError(
                "SubtitleHandler 需要通过构造函数传入 VolcengineCaptionService 实例"
            )
        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 {}
            mode = params.get("mode", "caption")
            volc_task_id = params.get("volc_task_id")
            project_id = params.get("project_id", "")
            video_path = params.get("video", params.get("video_path", ""))
            language = params.get("language", "zh")
            audio_text = params.get("audio_text", "")

            if volc_task_id:
                # 轮询阶段：不占用 slot，直接查询状态（使用标准 TaskStatus）
                try:
                    service = self._get_service()
                    if mode == "auto_align":
                        status = await service.query_auto_align_task_status(volc_task_id)
                    else:
                        status = await service.query_caption_task_status(volc_task_id)

                    if status.state == "completed":
                        result_data = status.result or {}
                        utterances_raw = result_data.get("utterances", [])
                        utterances = [
                            {
                                "text": u.get("text", ""),
                                "start_time": u.get("start_time", 0) or u.get("startTime", 0),
                                "end_time": u.get("end_time", 0) or u.get("endTime", 0),
                            }
                            for u in utterances_raw
                        ]
                        result_payload = {
                            "project_id": project_id,
                            "video_path": video_path,
                            "language": language,
                            "mode": mode,
                            "duration": result_data.get("duration", 0.0),
                            "utterances": utterances,
                        }
                        changes.append(
                            StateChange(task_id=task.task_id, field_path="status", value="completed")
                        )
                        changes.append(
                            StateChange(task_id=task.task_id, field_path="progress", value=100)
                        )
                        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=result_payload)
                        )
                    elif status.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=status.error_message or "字幕识别失败",
                            )
                        )
                    # state == "processing" / "pending"：不做任何变更，继续轮询
                except RuntimeError:
                    logger.error(f"[Subtitle {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"[Subtitle {task.task_id}] poll error: {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()
                    if mode == "auto_align":
                        if not audio_text:
                            raise ValueError("auto_align 模式需要提供 audio_text")
                        volc_task_id = await service.submit_auto_align_task(
                            audio_url=video_path,
                            audio_text=audio_text,
                        )
                    else:
                        volc_task_id = await service.submit_caption_task(
                            audio_url=video_path, language=language
                        )
                    if not volc_task_id:
                        raise ValueError("未返回任务ID")
                    params["volc_task_id"] = volc_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"[Subtitle {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"[Subtitle {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
