"""SSE options Greeks data provider.

上交所/东方财富期权希腊值与价值分析数据提供方。
"""

import akshare as ak
import pandas as pd

from ..cache import cache
from .greeks_base import OptionsGreeksDataProvider


class SSEOptionsGreeksProvider(OptionsGreeksDataProvider):
    """Adapter for SSE options derived datasets via AkShare.

    通过 AkShare 对接上交所（及其相关来源）期权衍生数据的适配器（Track A）。

    Supported endpoints:
        - Contract-level greeks (Sina): ak.option_sse_greeks_sina
        - Batch risk indicators by trade date (SSE): ak.option_risk_indicator_sse
        - Value analysis (EastMoney): ak.option_value_analysis_em
    """

    @cache(
        "options_greeks_cache",
        key=lambda self, symbol_or_date: f"sse_options_greeks_{symbol_or_date}",
    )
    def get_greeks(self, symbol_or_date: str) -> pd.DataFrame:
        """Fetch contract-level greeks and theoretical value.

        获取单合约希腊值与理论价值（来自新浪接口）。

        Args:
            symbol_or_date: Option contract code (e.g., '10003045').

        Returns:
            pd.DataFrame with columns: symbol, delta, gamma, theta, vega, rho, iv,
            theoretical_value

        Raises:
            ValueError: If request fails.
        """
        try:
            raw_df = ak.option_sse_greeks_sina(symbol_or_date)
            if raw_df.empty:
                return pd.DataFrame(
                    columns=["symbol", "delta", "gamma", "theta", "vega", "rho",
                             "iv", "theoretical_value"]
                )

            if "字段" not in raw_df.columns or "值" not in raw_df.columns:
                raise ValueError("Unexpected response schema for option_sse_greeks_sina.")

            data_dict = dict(zip(raw_df["字段"], raw_df["值"], strict=False))

            result = {
                "symbol": symbol_or_date,
                "delta": self._to_float(data_dict.get("Delta")),
                "gamma": self._to_float(data_dict.get("Gamma")),
                "theta": self._to_float(data_dict.get("Theta")),
                "vega": self._to_float(data_dict.get("Vega")),
                "rho": self._to_float(data_dict.get("Rho")),
                "iv": self._to_float(data_dict.get("隐含波动率")),
                "theoretical_value": self._to_float(data_dict.get("理论价值")),
            }

            return pd.DataFrame([result])
        except Exception as e:
            raise ValueError(f"Failed to fetch SSE options greeks: {e}") from e

    @cache(
        "options_risk_cache",
        key=lambda self, date: f"sse_options_risk_indicators_{date}",
    )
    def get_risk_indicators(self, date: str) -> pd.DataFrame:
        """Fetch SSE risk indicators for all contracts on a given date.

        获取上交所指定交易日的期权风险指标（批量披露）。

        Args:
            date: Trade date, format 'YYYYMMDD' or 'YYYY-MM-DD'.

        Returns:
            pd.DataFrame with columns: date, symbol, delta, gamma, theta, vega, rho, iv

        Raises:
            ValueError: If request fails.
        """
        try:
            trade_date = pd.to_datetime(date, errors="raise").strftime("%Y%m%d")
            out_date = pd.to_datetime(date, errors="coerce").date().isoformat()

            raw_df = ak.option_risk_indicator_sse(date=trade_date)
            if raw_df.empty:
                return pd.DataFrame(
                    columns=["date", "symbol", "delta", "gamma", "theta", "vega", "rho", "iv"]
                )

            df = raw_df.rename(
                columns={
                    "TRADE_DATE": "date",
                    "CONTRACT_SYMBOL": "symbol",
                    "DELTA_VALUE": "delta",
                    "THETA_VALUE": "theta",
                    "GAMMA_VALUE": "gamma",
                    "VEGA_VALUE": "vega",
                    "RHO_VALUE": "rho",
                    "IMPLC_VOLATLTY": "iv",
                }
            )

            if "date" in df.columns:
                df["date"] = out_date
            else:
                df.insert(0, "date", out_date)

            for col in ["delta", "gamma", "theta", "vega", "rho", "iv"]:
                if col in df.columns:
                    df[col] = pd.to_numeric(df[col], errors="coerce")

            columns = ["date", "symbol", "delta", "gamma", "theta", "vega", "rho", "iv"]
            return df[[c for c in columns if c in df.columns]].reset_index(drop=True)
        except Exception as e:
            raise ValueError(f"Failed to fetch SSE options risk indicators: {e}") from e

    @cache("options_value_cache", key=lambda self: "sse_options_value_analysis")
    def get_value_analysis(self) -> pd.DataFrame:
        """Fetch options value analysis from EastMoney.

        获取期权价值分析数据（时间价值、内在价值、隐含波动率、理论价格）。

        Returns:
            pd.DataFrame with columns: symbol, time_value, intrinsic_value, iv,
            theoretical_value

        Raises:
            ValueError: If request fails.
        """
        try:
            raw_df = ak.option_value_analysis_em()
            if raw_df.empty:
                return pd.DataFrame(
                    columns=["symbol", "time_value", "intrinsic_value", "iv", "theoretical_value"]
                )

            df = raw_df.rename(
                columns={
                    "期权代码": "symbol",
                    "时间价值": "time_value",
                    "内在价值": "intrinsic_value",
                    "隐含波动率": "iv",
                    "理论价格": "theoretical_value",
                }
            )

            for col in ["time_value", "intrinsic_value", "iv", "theoretical_value"]:
                if col in df.columns:
                    df[col] = pd.to_numeric(df[col], errors="coerce")

            columns = ["symbol", "time_value", "intrinsic_value", "iv", "theoretical_value"]
            return df[[c for c in columns if c in df.columns]].reset_index(drop=True)
        except Exception as e:
            raise ValueError(f"Failed to fetch options value analysis: {e}") from e

    def get_iv_by_series(self, symbol: str, date: str) -> pd.DataFrame:
        """Not supported by SSE provider.

        Raises:
            NotImplementedError: SSE does not provide IV by contract series.
        """
        raise NotImplementedError("SSE financial options source does not provide IV by series.")

    @staticmethod
    def _to_float(value: object) -> float | None:
        """Safely convert a value to float.

        Args:
            value: Any input value.

        Returns:
            float | None: Parsed float or None.
        """
        if value is None:
            return None
        try:
            return float(value)
        except (TypeError, ValueError):
            return None
