"""Stock Limit Price (涨跌停价格) interface.

Fetch daily limit up/down prices for all stocks from Tushare.
This interface retrieves the upper and lower limit prices for stocks,
which are typically available around 8:40 AM each trading day.
"""

from typing import override

import pandas as pd

from src.data.client import TushareClient
from src.data.api_wrappers.base_sync import DateBasedSync


def get_stk_limit(
    trade_date: str | None = None,
    start_date: str | None = None,
    end_date: str | None = None,
    ts_code: str | None = None,
    client: TushareClient | None = None,
) -> pd.DataFrame:
    """Fetch stock limit prices from Tushare.

    This interface retrieves daily limit up/down prices for stocks.
    Each trading day, limit prices are available around 8:40 AM.
    Supports fetching all stocks for a single date (preferred for efficiency)
    or date range data for specific stocks.

    Args:
        trade_date: Specific trade date (YYYYMMDD format).
            If provided, fetches all stocks for this date (most efficient).
        start_date: Start date (YYYYMMDD format).
            Used with end_date for date range queries.
        end_date: End date (YYYYMMDD format).
            Used with start_date for date range queries.
        ts_code: Stock code filter (optional).
            e.g., '000001.SZ', '600000.SH'
        client: Optional TushareClient instance for shared rate limiting.
            If None, creates a new client. For concurrent sync operations,
            pass a shared client to ensure proper rate limiting.

    Returns:
        pd.DataFrame with columns:
        - trade_date: Trade date (YYYYMMDD)
        - ts_code: Stock code
        - pre_close: Previous closing price
        - up_limit: Upper limit price (涨停价)
        - down_limit: Lower limit price (跌停价)

    Example:
        >>> # Get all stocks limit prices for a single date (most efficient)
        >>> data = get_stk_limit(trade_date='20240625')
        >>>
        >>> # Get date range data
        >>> data = get_stk_limit(start_date='20240101', end_date='20240131')
        >>>
        >>> # Get specific stock data
        >>> data = get_stk_limit(ts_code='000001.SZ', start_date='20240101', end_date='20240131')
    """
    client = client or TushareClient()

    # Build parameters
    params = {}
    if trade_date:
        params["trade_date"] = trade_date
    if start_date:
        params["start_date"] = start_date
    if end_date:
        params["end_date"] = end_date
    if ts_code:
        params["ts_code"] = ts_code

    # Fetch data
    data = client.query("stk_limit", **params)  # type: ignore

    # Rename date column if needed
    if "date" in data.columns:
        data = data.rename(columns={"date": "trade_date"})

    return data


class StkLimitSync(DateBasedSync):
    """Stock Limit Price data batch sync manager.

    Inherits from DateBasedSync, fetches data by date for all stocks.
    Each API call retrieves limit prices for all stocks on a specific date.

    Example:
        >>> sync = StkLimitSync()
        >>> results = sync.sync_all()  # Incremental sync
        >>> results = sync.sync_all(force_full=True)  # Full reload
        >>> preview = sync.preview_sync()  # Preview
    """

    table_name: str = "stk_limit"
    default_start_date: str = "20180101"

    # Table schema definition
    TABLE_SCHEMA: dict[str, str] = {
        "ts_code": "VARCHAR(16) NOT NULL",
        "trade_date": "DATE NOT NULL",
        "pre_close": "DOUBLE",
        "up_limit": "DOUBLE",
        "down_limit": "DOUBLE",
    }

    # Index definitions
    TABLE_INDEXES: list[tuple[str, list[str]]] = [
        ("idx_stk_limit_date_code", ["trade_date", "ts_code"]),
    ]

    # Primary key definition
    PRIMARY_KEY: tuple[str, str] = ("ts_code", "trade_date")

    @override
    def fetch_single_date(self, trade_date: str) -> pd.DataFrame:
        """Fetch limit prices for all stocks on a specific date.

        Args:
            trade_date: Trading date (YYYYMMDD)

        Returns:
            DataFrame with limit prices for all stocks on the date
        """
        # Use get_stk_limit to fetch all stocks for a single date
        data = get_stk_limit(
            trade_date=trade_date,
            client=self.client,  # Pass shared client for rate limiting
        )
        return data


def sync_stk_limit(
    force_full: bool = False,
    start_date: str | None = None,
    end_date: str | None = None,
    dry_run: bool = False,
) -> pd.DataFrame:
    """Sync stock limit prices to local DuckDB storage.

    This is the main entry point for stock limit price data synchronization.

    Args:
        force_full: If True, force full reload from default_start_date
        start_date: Manual start date override (YYYYMMDD)
        end_date: Manual end date override (defaults to today)
        dry_run: If True, only preview what would be synced without writing

    Returns:
        DataFrame with synced data

    Example:
        >>> # First sync (full load from default_start_date)
        >>> result = sync_stk_limit()
        >>>
        >>> # Subsequent syncs (incremental - only new data)
        >>> result = sync_stk_limit()
        >>>
        >>> # Force full reload
        >>> result = sync_stk_limit(force_full=True)
        >>>
        >>> # Manual date range
        >>> result = sync_stk_limit(start_date='20240101', end_date='20240131')
        >>>
        >>> # Dry run (preview only)
        >>> result = sync_stk_limit(dry_run=True)
    """
    sync_manager = StkLimitSync()
    return sync_manager.sync_all(
        force_full=force_full,
        start_date=start_date,
        end_date=end_date,
        dry_run=dry_run,
    )


def preview_stk_limit_sync(
    force_full: bool = False,
    start_date: str | None = None,
    end_date: str | None = None,
    sample_size: int = 3,
) -> dict[str, object]:
    """Preview stock limit price sync data volume and samples.

    This is the recommended way to check what would be synced before
    actually performing the synchronization.

    Args:
        force_full: If True, preview full sync from default_start_date
        start_date: Manual start date override
        end_date: Manual end date override (defaults to today)
        sample_size: Number of sample days to fetch for preview (default: 3)

    Returns:
        Dictionary with preview information:
        {
            'sync_needed': bool,
            'date_count': int,
            'start_date': str,
            'end_date': str,
            'estimated_records': int,
            'sample_data': pd.DataFrame,
            'mode': str,  # 'full', 'incremental', or 'none'
        }

    Example:
        >>> # Preview what would be synced
        >>> preview = preview_stk_limit_sync()
        >>>
        >>> # Preview full sync
        >>> preview = preview_stk_limit_sync(force_full=True)
        >>>
        >>> # Preview with more samples
        >>> preview = preview_stk_limit_sync(sample_size=5)
    """
    sync_manager = StkLimitSync()
    return sync_manager.preview_sync(
        force_full=force_full,
        start_date=start_date,
        end_date=end_date,
        sample_size=sample_size,
    )
