"""
火山引擎 OpenSpeech Provider
=============================

直接封装火山 OpenSpeech HTTP API：
- 字幕生成（/vc/submit + /vc/query）
- 自动打轴（/vc/ata/submit + /vc/ata/query）

使用 httpx.AsyncClient，支持外部注入（由 lifespan 管理生命周期）。
"""

from __future__ import annotations

import logging
from typing import Any

import httpx

from app.config import get_settings
from app.core.exceptions import PlatformError, PlatformErrorType

logger = logging.getLogger(__name__)


def _map_caption_error(status: int, message: str, code: int | None = None) -> PlatformError:
    """把火山字幕错误映射为标准 PlatformError"""
    error_mapping = {
        1001: (PlatformErrorType.BAD_REQUEST, False),
        1002: (PlatformErrorType.AUTH_FAILED, False),
        1003: (PlatformErrorType.RATE_LIMIT, True),
        1010: (PlatformErrorType.BAD_REQUEST, False),
        1011: (PlatformErrorType.BAD_REQUEST, False),
        1012: (PlatformErrorType.BAD_REQUEST, False),
        1013: (PlatformErrorType.BAD_REQUEST, False),
    }

    if code is not None and code in error_mapping:
        error_type, retryable = error_mapping[code]
        return PlatformError(
            message, platform="volcengine_caption",
            retryable=retryable, error_type=error_type,
            status_code=status,
        )

    http_mapping = {
        429: (PlatformErrorType.RATE_LIMIT, True),
        401: (PlatformErrorType.AUTH_FAILED, False),
        403: (PlatformErrorType.AUTH_FAILED, False),
        400: (PlatformErrorType.BAD_REQUEST, False),
        500: (PlatformErrorType.SERVER_ERROR, True),
        502: (PlatformErrorType.SERVER_ERROR, True),
        503: (PlatformErrorType.SERVER_ERROR, True),
    }
    error_type, retryable = http_mapping.get(status, (PlatformErrorType.UNKNOWN, False))
    return PlatformError(
        message, platform="volcengine_caption",
        retryable=retryable, error_type=error_type,
        status_code=status,
    )


class VolcengineCaptionProvider:
    """火山引擎字幕 Provider

    直接调用 OpenSpeech HTTP API，不做业务层处理（如格式转换、轮询）。
    """

    BASE_URL = "https://openspeech.bytedance.com/api/v1/vc"
    DEFAULT_TIMEOUT = 60.0

    def __init__(
        self,
        appid: str | None = None,
        token: str | None = None,
        client: httpx.AsyncClient | None = None,
    ):
        settings = get_settings()
        self.appid = appid or settings.VOLCENGINE_CAPTION_APPID or ""
        self.token = token or settings.VOLCENGINE_CAPTION_TOKEN or ""

        if not self.appid:
            raise PlatformError(
                "VOLCENGINE_CAPTION_APPID 未配置",
                platform="volcengine_caption",
                retryable=False,
                error_type=PlatformErrorType.BAD_REQUEST,
            )
        if not self.token:
            raise PlatformError(
                "VOLCENGINE_CAPTION_TOKEN 未配置",
                platform="volcengine_caption",
                retryable=False,
                error_type=PlatformErrorType.BAD_REQUEST,
            )

        if client is not None:
            self.client = client
            self._owns_client = False
        else:
            self.client = httpx.AsyncClient(timeout=self.DEFAULT_TIMEOUT)
            self._owns_client = True

    def _get_headers(self) -> dict:
        return {
            "Authorization": f"Bearer; {self.token}",
            "Content-Type": "application/json",
        }

    async def close(self) -> None:
        """关闭 HTTP 客户端"""
        if self._owns_client and self.client and not self.client.is_closed:
            await self.client.aclose()

    # ==================== 字幕生成 ====================

    async def submit_caption_task(
        self,
        audio_url: str,
        language: str = "zh-CN",
        caption_type: str = "auto",
        use_punc: bool = True,
        use_itn: bool = True,
        words_per_line: int = 46,
        max_lines: int = 1,
    ) -> dict[str, Any]:
        """提交字幕生成任务，返回 {id: task_id}"""
        params = {
            "appid": self.appid,
            "language": language,
            "caption_type": caption_type,
            "use_punc": str(use_punc),
            "use_itn": str(use_itn),
            "words_per_line": words_per_line,
            "max_lines": max_lines,
        }
        payload = {"url": audio_url}

        try:
            response = await self.client.post(
                f"{self.BASE_URL}/submit",
                params=params,
                json=payload,
                headers=self._get_headers(),
            )
            response.raise_for_status()
            data = response.json()
            if "id" not in data:
                raise _map_caption_error(500, f"提交任务失败: {data.get('message', '未知错误')}")
            return data
        except PlatformError:
            raise
        except httpx.HTTPStatusError as e:
            raise _map_caption_error(e.response.status_code, f"HTTP错误: {e.response.status_code}") from e
        except (httpx.NetworkError, httpx.TimeoutException) as e:
            raise PlatformError(
                f"字幕服务网络错误: {e}", platform="volcengine_caption",
                retryable=True, error_type=PlatformErrorType.TIMEOUT,
            ) from e
        except Exception as e:
            raise _map_caption_error(500, f"提交任务失败: {str(e)}") from e

    async def query_caption_task(
        self,
        task_id: str,
        blocking: bool = False,
    ) -> dict[str, Any]:
        """查询字幕任务结果，返回原始 JSON"""
        params = {
            "appid": self.appid,
            "id": task_id,
            "blocking": 1 if blocking else 0,
        }

        try:
            response = await self.client.get(
                f"{self.BASE_URL}/query",
                params=params,
                headers=self._get_headers(),
            )
            response.raise_for_status()
            return response.json()
        except PlatformError:
            raise
        except httpx.HTTPStatusError as e:
            raise _map_caption_error(e.response.status_code, f"HTTP错误: {e.response.status_code}") from e
        except (httpx.NetworkError, httpx.TimeoutException) as e:
            raise PlatformError(
                f"字幕服务网络错误: {e}", platform="volcengine_caption",
                retryable=True, error_type=PlatformErrorType.TIMEOUT,
            ) from e
        except Exception as e:
            raise _map_caption_error(500, f"查询任务失败: {str(e)}") from e

    # ==================== 自动打轴 ====================

    async def submit_auto_align_task(
        self,
        audio_url: str,
        audio_text: str,
        caption_type: str = "speech",
        sta_punc_mode: int = 3,
    ) -> dict[str, Any]:
        """提交自动字幕打轴任务，返回 {id: task_id}"""
        params = {
            "appid": self.appid,
            "caption_type": caption_type,
            "sta_punc_mode": sta_punc_mode,
        }
        payload = {"url": audio_url, "audio_text": audio_text}

        try:
            response = await self.client.post(
                f"{self.BASE_URL}/ata/submit",
                params=params,
                json=payload,
                headers=self._get_headers(),
            )
            response.raise_for_status()
            data = response.json()
            if "id" not in data:
                raise _map_caption_error(500, f"提交打轴任务失败: {data.get('message', '未知错误')}")
            return data
        except PlatformError:
            raise
        except Exception as e:
            raise _map_caption_error(500, f"提交打轴任务失败: {str(e)}") from e

    async def query_auto_align_task(
        self,
        task_id: str,
        blocking: bool = False,
    ) -> dict[str, Any]:
        """查询打轴任务结果，返回原始 JSON"""
        params = {
            "appid": self.appid,
            "id": task_id,
            "blocking": 1 if blocking else 0,
        }

        try:
            response = await self.client.get(
                f"{self.BASE_URL}/ata/query",
                params=params,
                headers=self._get_headers(),
            )
            response.raise_for_status()
            return response.json()
        except PlatformError:
            raise
        except Exception as e:
            raise _map_caption_error(500, f"查询打轴任务失败: {str(e)}") from e
