from __future__ import annotations

import json
from typing import Any

from backend.llm import transport as llm_transport
from backend.features.screener.catalog import FACTOR_FIELDS, REGIMES


class LLMCompilerError(RuntimeError):
    pass


def test_llm_connection(
    api_key: str,
    base_url: str,
    model: str,
    timeout: int = 30,
) -> dict[str, Any]:
    if not api_key or not model:
        raise LLMCompilerError("API Key 或模型未配置。")
    try:
        result = llm_transport.chat_completion(
            api_key=api_key,
            base_url=base_url,
            model=model,
            messages=[{"role": "user", "content": "只回复 OK"}],
            timeout=timeout,
            user_agent="XiaobaiReviewWeb/0.5",
        )
        reply = str(result.content).strip()
    except llm_transport.OpenAIHTTPError as exc:
        raise LLMCompilerError(exc.describe("模型连接测试失败")) from exc
    except llm_transport.OpenAITransportError as exc:
        raise LLMCompilerError(f"模型连接测试失败：{exc}") from exc
    return {
        "ok": True,
        "model": model,
        "reply": reply[:100],
        "latency_ms": result.latency_ms,
    }


def compile_strategy_with_llm(
    prompt: str,
    regime: str,
    api_key: str,
    base_url: str,
    model: str,
    timeout: int = 45,
) -> dict[str, Any]:
    if not api_key or not model:
        raise LLMCompilerError("尚未配置 LLM API Key 或模型。")
    schema = {
        "name": "策略名称",
        "description": "策略说明",
        "regimes": [regime],
        "formula": {
            "universe": {"exclude_st": True, "listed_days_min": 120},
            "filters": [{"field": "return_5d", "op": ">=", "value": 0}],
            "score": [{"field": "sector_strength", "weight": 0.3, "direction": "desc"}],
            "limit": 15,
            "min_score": 0.55,
        },
    }
    system_prompt = (
        "你是A股量化策略编译器。只输出JSON对象，不输出Markdown。"
        "不得生成Python、SQL、网络请求或未提供的因子。"
        f"当前市场阶段为{REGIMES.get(regime, regime)}。"
        f"可用因子为：{json.dumps(FACTOR_FIELDS, ensure_ascii=False)}。"
        "运算符只能使用 >, >=, <, <=, ==, !=, between, in。"
        "score权重均大于0且不超过1，direction只能是asc或desc。"
        "退潮和冰点策略必须提高门槛并允许结果为空。"
        f"严格遵循以下结构：{json.dumps(schema, ensure_ascii=False)}"
    )
    try:
        result = llm_transport.chat_completion(
            api_key=api_key,
            base_url=base_url,
            model=model,
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": prompt[:3000]},
            ],
            timeout=timeout,
            user_agent="XiaobaiReviewWeb/0.4",
        )
        content = result.content.strip()
        if content.startswith("```"):
            content = content.strip("`")
            if content.startswith("json"):
                content = content[4:].strip()
        compiled = json.loads(content)
    except llm_transport.OpenAIHTTPError as exc:
        raise LLMCompilerError(exc.describe("LLM 策略编译失败")) from exc
    except (llm_transport.OpenAITransportError, json.JSONDecodeError) as exc:
        raise LLMCompilerError(f"LLM 策略编译失败：{exc}") from exc
    compiled["compiler"] = "llm"
    compiled["model"] = model
    return compiled
