from __future__ import annotations

from datetime import datetime, timedelta
from typing import Any

from backend.data.numbers import finite_number as _number
from backend.data.providers.tushare_transport import TushareError


class IndexMixin:
    def market_indices(self, requested_date: str, lookback_days: int = 45) -> dict[str, Any]:
        trade_date, _ = self.resolve_trade_context(requested_date)
        end = datetime.strptime(trade_date, "%Y%m%d")
        start_date = (end - timedelta(days=max(30, lookback_days * 2))).strftime("%Y%m%d")
        index_names = {
            "000001.SH": "上证指数",
            "399001.SZ": "深证成指",
            "399006.SZ": "创业板指",
        }
        indices = []
        for ts_code, name in index_names.items():
            rows = self.query(
                "index_daily",
                {"ts_code": ts_code, "start_date": start_date, "end_date": trade_date},
                "ts_code,trade_date,close,pct_chg,vol,amount",
            )
            rows.sort(key=lambda item: str(item.get("trade_date") or ""))
            if not rows:
                continue
            latest = rows[-1]
            close = _number(latest.get("close"))
            close_5d = _number(rows[-6].get("close")) if len(rows) >= 6 else _number(rows[0].get("close"))
            close_20d = _number(rows[-21].get("close")) if len(rows) >= 21 else _number(rows[0].get("close"))
            indices.append(
                {
                    "ts_code": ts_code,
                    "name": name,
                    "trade_date": str(latest.get("trade_date") or trade_date),
                    "close": close,
                    "pct_chg": round(_number(latest.get("pct_chg")), 3),
                    "return_5d": round((close / close_5d - 1) * 100, 3) if close_5d else 0,
                    "return_20d": round((close / close_20d - 1) * 100, 3) if close_20d else 0,
                    "amount_billion": round(_number(latest.get("amount")) / 100000, 2),
                }
            )
        if not indices:
            raise TushareError(f"No index data returned for {trade_date}")
        return {
            "trade_date": trade_date,
            "source": "tushare",
            "realtime": False,
            "precise": all(item["trade_date"] == trade_date for item in indices),
            "indices": indices,
            "aggregate": {
                "average_pct_chg": round(sum(item["pct_chg"] for item in indices) / len(indices), 3),
                "average_return_5d": round(sum(item["return_5d"] for item in indices) / len(indices), 3),
                "average_return_20d": round(sum(item["return_20d"] for item in indices) / len(indices), 3),
            },
        }

    def realtime_market_indices(self, requested_date: str) -> dict[str, Any]:
        trade_date, _ = self.resolve_trade_context(requested_date)
        index_names = {
            "000001.SH": "上证指数",
            "399001.SZ": "深证成指",
            "399006.SZ": "创业板指",
        }
        rows = self.query("rt_idx_k", {"ts_code": ",".join(index_names)}, "")
        row_map = {str(row.get("ts_code") or ""): row for row in rows}
        indices = []
        for ts_code, name in index_names.items():
            row = row_map.get(ts_code)
            if not row:
                continue
            close = _number(row.get("close"))
            previous_close = _number(row.get("pre_close"))
            if close <= 0 or previous_close <= 0:
                continue
            history = self.query(
                "index_daily",
                {
                    "ts_code": ts_code,
                    "start_date": (datetime.strptime(trade_date, "%Y%m%d") - timedelta(days=20)).strftime("%Y%m%d"),
                    "end_date": trade_date,
                },
                "ts_code,trade_date,close,pct_chg",
            )
            history.sort(key=lambda item: str(item.get("trade_date") or ""))
            previous_closes = [
                _number(item.get("close")) for item in history
                if str(item.get("trade_date") or "") < trade_date and _number(item.get("close")) > 0
            ]
            close_5d = previous_closes[-5] if len(previous_closes) >= 5 else previous_closes[0] if previous_closes else previous_close
            indices.append(
                {
                    "ts_code": ts_code,
                    "name": str(row.get("name") or name).strip(),
                    "trade_date": trade_date,
                    "close": close,
                    "pct_chg": round((close / previous_close - 1) * 100, 3),
                    "return_5d": round((close / close_5d - 1) * 100, 3) if close_5d else 0,
                    "amount_billion": round(_number(row.get("amount")) / 100000000, 2),
                }
            )
        if len(indices) != len(index_names):
            raise TushareError("Realtime index quotes are incomplete")
        return {
            "trade_date": trade_date,
            "source": "tushare_rt_idx_k",
            "realtime": True,
            "precise": True,
            "indices": indices,
            "aggregate": {
                "average_pct_chg": round(sum(item["pct_chg"] for item in indices) / len(indices), 3),
                "average_return_5d": round(sum(item["return_5d"] for item in indices) / len(indices), 3),
                "average_return_20d": 0,
            },
        }
