from __future__ import annotations

from typing import Any

from backend.data.numbers import finite_number as _number
from backend.data.providers.tushare_helpers import _display_time, _prices_equal


class DailyMarketMixin:
    def resolve_trade_context(self, requested: str) -> tuple[str, str]:
        requested_rows = self.query(
            "trade_cal",
            {"exchange": "SSE", "start_date": requested, "end_date": requested},
            "cal_date,is_open,pretrade_date",
        )
        if not requested_rows:
            trade_date = requested
        else:
            row = requested_rows[0]
            trade_date = row["cal_date"] if row.get("is_open") == 1 else row.get("pretrade_date", requested)

        resolved_rows = self.query(
            "trade_cal",
            {"exchange": "SSE", "start_date": trade_date, "end_date": trade_date},
            "cal_date,is_open,pretrade_date",
        )
        previous = resolved_rows[0].get("pretrade_date") if resolved_rows else ""
        return trade_date, previous or trade_date

    def _load_daily(self, trade_date: str) -> list[dict[str, Any]]:
        return self.query(
            "daily",
            {"trade_date": trade_date},
            "ts_code,trade_date,open,high,low,close,pct_chg,amount",
        )

    def _load_limit_type(self, trade_date: str, limit_type: str) -> list[dict[str, Any]]:
        fields = (
            "trade_date,ts_code,industry,name,close,pct_chg,amount,limit_amount,"
            "float_mv,total_mv,turnover_ratio,fd_amount,first_time,last_time,"
            "open_times,up_stat,limit_times"
        )
        rows = self.query(
            "limit_list_d",
            {"trade_date": trade_date, "limit_type": limit_type},
            fields,
        )
        for row in rows:
            row["limit_type"] = limit_type
            row["amount_unit"] = "yuan"
        return rows

    def _load_limit_lists(self, trade_date: str) -> list[dict[str, Any]]:
        rows: list[dict[str, Any]] = []
        for limit_type in ("U", "D", "Z"):
            rows.extend(self._load_limit_type(trade_date, limit_type))
        return rows

    def _derive_limits(
        self,
        trade_date: str,
        daily: list[dict[str, Any]],
        price_limits: list[dict[str, Any]] | None = None,
        basic_rows: list[dict[str, Any]] | None = None,
        previous_limit_rows: list[dict[str, Any]] | None = None,
        capital_rows: list[dict[str, Any]] | None = None,
    ) -> list[dict[str, Any]]:
        if price_limits is None:
            price_limits = self.query(
                "stk_limit",
                {"trade_date": trade_date},
                "ts_code,trade_date,up_limit,down_limit",
            )
        limit_map = {row["ts_code"]: row for row in price_limits}
        if basic_rows is None:
            basic_rows = self.query(
                "stock_basic",
                {"list_status": "L"},
                "ts_code,name,industry",
            )
        basic_map = {row["ts_code"]: row for row in basic_rows}
        previous_limit_map = {
            str(row.get("ts_code") or ""): row for row in (previous_limit_rows or [])
        }
        capital_map = {
            str(row.get("ts_code") or ""): row for row in (capital_rows or [])
        }

        result: list[dict[str, Any]] = []
        for row in daily:
            bounds = limit_map.get(row.get("ts_code"))
            if not bounds or row.get("close") is None:
                continue
            limit_type = ""
            if _prices_equal(row["close"], bounds.get("up_limit")):
                limit_type = "U"
            elif _prices_equal(row["close"], bounds.get("down_limit")):
                limit_type = "D"
            elif _prices_equal(row.get("high"), bounds.get("up_limit")):
                limit_type = "Z"
            if not limit_type:
                continue
            basic = basic_map.get(row["ts_code"], {})
            previous_limit = previous_limit_map.get(str(row.get("ts_code") or ""), {})
            streak = (
                max(1, int(_number(previous_limit.get("limit_times"), 1)) + 1)
                if limit_type == "U" and previous_limit
                else 1
            )
            item = {
                    **row,
                    "name": basic.get("name", "--"),
                    "industry": basic.get("industry") or "其他",
                    "limit_type": limit_type,
                    "limit_times": streak,
                    "open_times": 1 if limit_type == "Z" else 0,
                    "amount_unit": row.get("amount_unit") or "thousand_yuan",
                }
            if row.get("amount_unit") == "yuan":
                capital = capital_map.get(str(row.get("ts_code") or ""), {})
                if not capital and capital_rows is None:
                    capital = self._latest_capital(str(row.get("ts_code") or ""), trade_date)
                float_share = _number(capital.get("float_share"))
                item["turnover_ratio"] = (
                    _number(row.get("vol")) / float_share / 100 if float_share else 0
                )
                item["turnover_source"] = (
                    "rt_volume/latest_float_share" if float_share else "unavailable"
                )
                item["capital_trade_date"] = str(capital.get("trade_date") or "")
            result.append(item)
        return result

    @staticmethod
    def _normalize_limit(row: dict[str, Any], status: str) -> dict[str, Any]:
        amount = _number(row.get("amount"))
        if row.get("amount_unit") == "thousand_yuan":
            amount_billion = amount / 100000
        else:
            amount_billion = amount / 100000000
        return {
            "code": str(row.get("ts_code", "")).split(".")[0],
            "ts_code": row.get("ts_code", ""),
            "name": row.get("name") or "--",
            "price": _number(row.get("close")),
            "change": _number(row.get("pct_chg")),
            "sector": row.get("industry") or "其他",
            "reason": row.get("industry") or "待补充",
            "first_time": _display_time(row.get("first_time")),
            "last_time": _display_time(row.get("last_time")),
            "open_times": int(_number(row.get("open_times"))),
            "streak": max(1, int(_number(row.get("limit_times"), 1))),
            "turnover_rate": _number(row.get("turnover_ratio")),
            "turnover_source": row.get("turnover_source") or "provider",
            "capital_trade_date": row.get("capital_trade_date") or "",
            "amount_billion": round(amount_billion, 2),
            "seal_amount_million": round(_number(row.get("fd_amount")) / 10000, 0),
            "float_mv_billion": round(_number(row.get("float_mv")) / 100000000, 1),
            "status": status,
        }
