"""品牌引用检测服务 - 替代 workers/llm_adapter.py

使用 LLMFactory (System 1) 替代直接 OpenAI 客户端调用 (System 3)，
统一 LLM 调用路径，消除重复的适配器层。
"""
import json
import logging
from typing import Optional

from app.config import settings
from app.schemas.scoring import CitationResult
from app.services.llm.base import LLMError
from app.services.llm.factory import LLMFactory
from app.utils.json_extractor import extract_json

logger = logging.getLogger(__name__)

BRAND_CITATION_PROMPT = """分析以下AI搜索查询中是否提到了目标品牌。

查询关键词: {keyword}
目标品牌: {brand_name}
品牌别名: {brand_aliases}

返回JSON格式:
{{"cited": true/false, "position": 1, "citation_text": "...", "sentiment": "positive/neutral/negative", "confidence": 0.95}}
"""

VALID_SENTIMENTS = {"positive", "neutral", "negative"}


class BrandCitationLLMService:
    """使用LLM进行品牌引用检测的服务

    通过 LLMFactory 获取 Provider 实例，遵循 System 1 的统一调用路径。
    替代旧版 LLMAdapter (System 3) 的直接 OpenAI 客户端调用。
    """

    def __init__(self, provider_name: Optional[str] = None, model: Optional[str] = None):
        """
        Args:
            provider_name: 指定LLM提供商名称（如 "openai", "deepseek"），
                           为None时使用默认配置
            model: 覆盖默认模型名
        """
        self._provider_name = provider_name
        self._model = model

    def _get_provider(self):
        """获取LLM Provider实例"""
        if self._provider_name:
            return LLMFactory.create(provider=self._provider_name, model=self._model)
        return LLMFactory.get_default()

    def _build_prompt(self, keyword: str, brand_name: str, brand_aliases: list[str]) -> str:
        """构建品牌引用检测Prompt

        Args:
            keyword: 搜索关键词
            brand_name: 目标品牌名
            brand_aliases: 品牌别名列表

        Returns:
            格式化后的Prompt字符串
        """
        aliases_str = ", ".join(brand_aliases) if brand_aliases else "无"
        return BRAND_CITATION_PROMPT.format(
            keyword=keyword,
            brand_name=brand_name,
            brand_aliases=aliases_str,
        )

    def _parse_response(self, data: dict) -> CitationResult:
        """解析LLM返回的JSON数据为CitationResult

        Args:
            data: LLM返回的JSON字典

        Returns:
            CitationResult对象

        Raises:
            LLMError: 响应缺少必需字段或解析失败
        """
        try:
            # 验证必需字段
            required_fields = ['cited', 'sentiment', 'confidence']
            for field in required_fields:
                if field not in data:
                    raise LLMError(
                        f"响应缺少必需字段: {field}",
                        provider="brand_citation",
                    )

            cited = bool(data['cited'])

            # 验证sentiment
            sentiment = str(data.get('sentiment', 'neutral')).lower()
            if sentiment not in VALID_SENTIMENTS:
                sentiment = 'neutral'

            # 验证position
            position = data.get('position')
            if position is not None:
                position = int(position)
                if position < 1:
                    position = None

            # 验证confidence（钳制到0.0-1.0）
            confidence = float(data.get('confidence', 0.5))
            confidence = max(0.0, min(1.0, confidence))

            # 截断过长的citation_text
            citation_text = data.get('citation_text')
            if citation_text and len(citation_text) > 500:
                citation_text = citation_text[:500]

            return CitationResult(
                cited=cited,
                position=position,
                citation_text=citation_text,
                sentiment=sentiment,
                confidence=confidence,
            )

        except (ValueError, TypeError) as e:
            raise LLMError(
                f"解析响应失败: {e}",
                provider="brand_citation",
            ) from e

    async def query_brand_citation(
        self,
        keyword: str,
        brand_name: str,
        brand_aliases: list[str],
    ) -> CitationResult:
        """查询品牌在AI搜索结果中的引用情况

        Args:
            keyword: 搜索关键词
            brand_name: 目标品牌名
            brand_aliases: 品牌别名列表

        Returns:
            CitationResult: 引用检测结果

        Raises:
            LLMError: 当LLM被禁用或调用失败时
        """
        if not settings.ENABLE_LLM:
            raise LLMError(
                "LLM引用检测未启用。请在环境变量中设置 ENABLE_LLM=True 并配置 API Key",
                provider="brand_citation",
            )

        provider = self._get_provider()
        prompt = self._build_prompt(keyword, brand_name, brand_aliases)

        messages = [{"role": "user", "content": prompt}]
        response = await provider.chat(messages, temperature=0.1, max_tokens=500)

        if not response.content:
            raise LLMError(
                "API返回空响应",
                provider="brand_citation",
            )

        # 提取JSON（可能包裹在```json block中）
        try:
            json_str = extract_json(response.content)
        except ValueError as e:
            raise LLMError(
                str(e),
                provider="brand_citation",
            ) from e

        data = json.loads(json_str)
        return self._parse_response(data)
