import json
import re

import numpy as np
from llm.client import LLMClient


class NumpyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, (np.integer,)):
            return int(obj)
        if isinstance(obj, (np.floating,)):
            return float(obj)
        if isinstance(obj, np.ndarray):
            return obj.tolist()
        return super().default(obj)


class StockAnalyzer:
    def __init__(self, client: LLMClient = None):
        self.client = client or LLMClient()

    def analyze_sentiment(self, news_list: list) -> dict:
        if not self.client.is_available() or not news_list:
            return {"sentiment_score": 0, "confidence": 0, "summary": ""}

        system = """你是一个专业的A股市场分析师。分析以下新闻对股票的影响。
对每条新闻，输出JSON格式：
{"items": [{"title": "标题", "sentiment": 0到1之间的分数, "impact": "简短影响分析"}]}
sentiment: 0.8-1.0=强烈利好, 0.6-0.8=利好, 0.4-0.6=中性, 0.2-0.4=利空, 0-0.2=强烈利空
只输出JSON，不要其他内容。"""

        news_text = "\n".join(f"- {n}" for n in news_list[:20])
        resp = self.client.chat(
            f"分析以下新闻对A股的影响:\n{news_text}",
            system, temperature=0.1
        )

        try:
            match = re.search(r'\{.*\}', resp, re.DOTALL)
            if match:
                data = json.loads(match.group())
                items = data.get("items", [])
                if items:
                    avg_score = sum(i.get("sentiment", 0.5) for i in items) / len(items)
                    return {
                        "sentiment_score": round(avg_score, 3),
                        "confidence": 0.7,
                        "summary": f"分析了{len(items)}条新闻",
                        "items": items,
                    }
        except (json.JSONDecodeError, KeyError):
            pass

        return {"sentiment_score": 0.5, "confidence": 0.3, "summary": "解析失败"}

    def analyze_limit_up(self, stock_info: dict) -> dict:
        if not self.client.is_available():
            return {"limit_up_type": "unknown", "analysis": ""}

        system = """分析A股涨停板。判断涨停原因类型。
输出JSON: {"type": "strong|weak|policy|sector|speculation", "confidence": 0-1, "reason": "简短理由"}
- strong: 基本面驱动的强势涨停
- weak: 资金驱动的弱势涨停（封单小、多次开板）
- policy: 政策利好驱动
- sector: 板块联动涨停
- speculation: 纯投机炒作
只输出JSON。"""

        info_text = json.dumps(stock_info, ensure_ascii=False, indent=2)
        resp = self.client.chat(f"分析涨停股票:\n{info_text}", system, temperature=0.1)

        try:
            match = re.search(r'\{.*\}', resp, re.DOTALL)
            if match:
                return json.loads(match.group())
        except (json.JSONDecodeError, KeyError):
            pass
        return {"type": "unknown", "confidence": 0, "analysis": resp[:200]}

    def generate_report(self, stocks: list, market_context: dict) -> str:
        if not self.client.is_available():
            return self._fallback_report(stocks)

        system = """你是一个专业的A股超短线选股顾问。根据提供的选股结果和市场环境，生成简洁的每日选股报告。
报告格式:
1. 市场环境概述 (2-3句)
2. 今日推荐股票表格 (代码、名称、得分、推荐理由) — 必须使用且仅使用下面提供的股票，不要添加或替换任何股票，表格不要排名列
3. 风险提示
语言简洁专业，避免废话。严格按ML模型排名输出，不要自行调整顺序或更换股票。"""

        stocks_text = json.dumps(stocks[:10], ensure_ascii=False, indent=2, cls=NumpyEncoder)
        context_text = json.dumps(market_context, ensure_ascii=False, indent=2, cls=NumpyEncoder)
        prompt = f"市场环境:\n{context_text}\n\n推荐股票:\n{stocks_text}"

        return self.client.chat(prompt, system, temperature=0.5)

    def _fallback_report(self, stocks: list) -> str:
        lines = ["# 每日选股报告\n"]
        lines.append("| 代码 | 名称 | 得分 |")
        lines.append("|------|------|------|")
        for s in stocks[:10]:
            lines.append(f"| {s.get('code', '')} | {s.get('name', '')} | {s.get('total_score', 0):.3f} |")
        lines.append("\n*LLM未配置，仅显示ML模型选股结果*")
        return "\n".join(lines)
