"""Futures derived / report data provider interface.

期货衍生/报表类数据提供方抽象接口（Track A），
包括基差、展期收益率、持仓排名、仓单与库存等。
"""

from abc import ABC, abstractmethod
from typing import Literal

import pandas as pd

FuturesExchange = Literal["shfe", "dce", "czce", "cffex", "gfex"]
WarehouseExchange = Literal["shfe", "dce", "czce", "gfex"]


class FuturesDerivedDataProvider(ABC):
    """Abstract base class for futures derived/report data providers.

    期货衍生/报表类数据提供方抽象接口（Track A）。

    Notes:
        - All methods return standardized ``pd.DataFrame``.
        - ``symbol`` refers to futures variety code (品种代码), e.g. 'RB', 'AL'.
    """

    @abstractmethod
    def get_basis(self, date: str, symbol: str) -> pd.DataFrame:
        """Fetch spot price and basis for a given trade date and variety.

        获取指定交易日与品种的现货价格与期货基差。

        Args:
            date: 交易日, format 'YYYYMMDD' or 'YYYY-MM-DD'.
            symbol: 品种代码, e.g. 'RB', 'AL'.

        Returns:
            pd.DataFrame:
            - date: 交易日
            - symbol: 品种代码
            - spot_price: 现货价格
            - near_contract: 临近交割合约代码
            - near_price: 临近合约结算价
            - main_contract: 主力合约代码
            - main_price: 主力合约结算价
            - near_basis: 临近合约基差
            - main_basis: 主力合约基差
            - near_basis_rate: 临近合约基差率
            - main_basis_rate: 主力合约基差率

        Raises:
            ValueError: If inputs are invalid.
        """
        pass

    @abstractmethod
    def get_roll_yield(self, date: str, symbol: str) -> pd.DataFrame:
        """Fetch roll yield for a given trade date and variety.

        获取指定交易日与品种的展期收益率。

        Args:
            date: 交易日, format 'YYYYMMDD' or 'YYYY-MM-DD'.
            symbol: 品种代码, e.g. 'RB', 'AL'.

        Returns:
            pd.DataFrame:
            - date: 交易日
            - symbol: 品种代码
            - roll_yield: 展期收益率
            - near_contract: 近月合约
            - deferred_contract: 远月合约

        Raises:
            ValueError: If inputs are invalid.
        """
        pass

    @abstractmethod
    def get_position_ranking(
        self, date: str, symbol: str, exchange: FuturesExchange
    ) -> pd.DataFrame:
        """Fetch position ranking table.

        获取指定交易日、品种与交易所的会员持仓排名数据。

        Args:
            date: 交易日, format 'YYYYMMDD' or 'YYYY-MM-DD'.
            symbol: 品种代码, e.g. 'RB', 'AL'.
            exchange: 交易所代码 ('shfe', 'dce', 'czce', 'cffex', 'gfex').

        Returns:
            pd.DataFrame:
            - date: 交易日
            - exchange: 交易所
            - variety: 品种代码
            - contract: 合约代码
            - rank: 排名
            - volume_member: 成交量排名会员
            - volume: 成交量
            - volume_change: 成交量变化
            - long_member: 多单排名会员
            - long_open_interest: 多单持仓量
            - long_open_interest_change: 多单持仓量变化
            - short_member: 空单排名会员
            - short_open_interest: 空单持仓量
            - short_open_interest_change: 空单持仓量变化

        Raises:
            ValueError: If inputs are invalid.
        """
        pass

    @abstractmethod
    def get_warehouse_receipt(self, date: str, exchange: WarehouseExchange) -> pd.DataFrame:
        """Fetch warehouse receipt report.

        获取指定交易日与交易所的仓单日报数据。

        Args:
            date: 交易日, format 'YYYYMMDD' or 'YYYY-MM-DD'.
            exchange: 交易所代码 ('shfe', 'dce', 'czce', 'gfex').

        Returns:
            pd.DataFrame:
            - date: 交易日
            - exchange: 交易所
            - symbol: 品种代码
            - warehouse: 仓库/分库
            - receipt_prev: 昨日仓单量
            - receipt: 今日仓单量
            - receipt_change: 增减

        Raises:
            ValueError: If inputs are invalid.
        """
        pass

    @abstractmethod
    def get_inventory(self, symbol: str) -> pd.DataFrame:
        """Fetch futures inventory data for a given variety.

        获取指定品种的库存数据。

        Args:
            symbol: 品种代码, e.g. 'RB', 'AL'.

        Returns:
            pd.DataFrame:
            - date: 日期
            - symbol: 品种代码
            - inventory: 库存
            - inventory_change: 库存变化 (if available)

        Raises:
            ValueError: If inputs are invalid.
        """
        pass
