"""
Tushare 数据源封装。

与 AkShareSource 保持相同接口，作为平替/备份数据源。
"""

import os
import time

import pandas as pd
import tushare as ts

# 确保 .env 已加载（无论从哪个路径导入）
import config.settings  # noqa: F401


class TushareSource:
    """Tushare 数据源。"""

    def __init__(self, token: str | None = None):
        token = token or os.getenv("TUSHARE_TOKEN", "")
        if not token:
            self._pro = None
        else:
            ts.set_token(token)
            self._pro = ts.pro_api()

    @property
    def available(self) -> bool:
        return self._pro is not None

    def _ensure_pro(self):
        if self._pro is None:
            raise RuntimeError("Tushare token 未配置，请在 .env 中设置 TUSHARE_TOKEN")

    # ── 股票列表 ──────────────────────────────────────────

    def fetch_stock_list(self) -> pd.DataFrame:
        """获取 A 股股票列表。"""
        self._ensure_pro()
        fields = "ts_code,name,area,industry,market,list_date,is_hs"
        df = self._pro.stock_basic(
            exchange="", list_status="L",
            fields=fields,
        )
        if df is None or df.empty:
            return pd.DataFrame()
        return df[["ts_code", "name"]]

    # ── 日线数据 ──────────────────────────────────────────

    def fetch_daily(
        self, ts_code: str, start: str, end: str | None = None
    ) -> pd.DataFrame:
        """
        获取单只股票日线行情。

        参数:
            ts_code: 如 '000001.SZ'
            start: 'YYYYMMDD'
            end: 'YYYYMMDD'
        """
        self._ensure_pro()
        end = end or time.strftime("%Y%m%d")

        df = self._pro.daily(
            ts_code=ts_code,
            start_date=start,
            end_date=end,
            fields="ts_code,trade_date,open,high,low,close,pre_close,change,pct_chg,vol,amount,turnover_rate",
        )
        if df is None or df.empty:
            return pd.DataFrame()

        # 前复权因子
        try:
            adj = self._pro.adj_factor(ts_code=ts_code, start_date=start, end_date=end)
            if adj is not None and not adj.empty:
                df = df.merge(adj[["trade_date", "adj_factor"]], on="trade_date", how="left")
                for col in ["open", "high", "low", "close", "pre_close"]:
                    if col in df.columns and "adj_factor" in df.columns:
                        df[col] = (df[col] * df["adj_factor"]).round(2)
                df = df.drop(columns=["adj_factor"])
        except Exception:
            pass

        df["trade_date"] = df["trade_date"].astype(str)
        return df

    # ── 指数日线 ──────────────────────────────────────────

    def fetch_index_daily(
        self, ts_code: str, start: str, end: str | None = None
    ) -> pd.DataFrame:
        """
        获取指数日线行情。

        Tushare index_daily 接口。
        """
        self._ensure_pro()
        end = end or time.strftime("%Y%m%d")
        df = self._pro.index_daily(
            ts_code=ts_code,
            start_date=start, end_date=end,
            fields="ts_code,trade_date,open,high,low,close,pre_close,change,pct_chg,vol,amount",
        )
        if df is None or df.empty:
            return pd.DataFrame()
        df["trade_date"] = df["trade_date"].astype(str)
        return df

    # ── 财务数据 ──────────────────────────────────────────

    def fetch_financial(self, ts_code: str) -> pd.DataFrame:
        """获取单只股票核心财务指标。"""
        self._ensure_pro()
        fields = (
            "ts_code,end_date,roe,roa,grossprofit_margin,netprofit_margin,"
            "debt_to_assets,eps,dt_eps,bps,pe,pb,"
            "total_revenue,revenue_yoy,n_income,n_income_yoy"
        )
        df = self._pro.fina_indicator(
            ts_code=ts_code,
            fields=fields,
        )
        if df is None or df.empty:
            return pd.DataFrame()

        df = df.rename(columns={
            "grossprofit_margin": "gross_profit_margin",
            "netprofit_margin": "net_profit_margin",
            "dt_eps": "eps_diluted",
            "bps": "bvps",
            "revenue_yoy": "total_revenue_yoy",
            "n_income": "net_profit",
            "n_income_yoy": "net_profit_yoy",
        })
        df["end_date"] = df["end_date"].astype(str)
        return df
