from __future__ import annotations

from dataclasses import dataclass

from .audit_log import AuditLogger
from .config import Settings
from .exchange import BinanceSpotClient
from .models import TradingMode
from .storage import Storage


@dataclass(frozen=True)
class SpotTradeSyncResult:
    status: str
    reason: str
    scanned_symbols: int
    fetched_trades: int
    inserted_trades: int


def sync_spot_trade_fills(
    settings: Settings,
    *,
    exchange_client=None,
    storage: Storage | None = None,
    symbols: tuple[str, ...] | None = None,
) -> SpotTradeSyncResult:
    if settings.mode not in {TradingMode.LIVE, TradingMode.TESTNET_LIVE}:
        return SpotTradeSyncResult(
            status="rejected",
            reason="live or testnet_live mode required",
            scanned_symbols=0,
            fetched_trades=0,
            inserted_trades=0,
        )

    storage = storage or Storage(settings.database_path)
    storage.initialize()
    exchange = exchange_client if exchange_client is not None else BinanceSpotClient(
        api_key=settings.api_key,
        api_secret=settings.api_secret.get_secret_value(),
        base_url=settings.rest_base_url,
        base_urls=settings.rest_base_urls,
        recv_window=settings.recv_window,
        proxy_url=settings.proxy_url,
        audit_logger=AuditLogger(settings.database_path.parent / "logs"),
    )

    normalized_symbols = _sync_symbols(settings, symbols)
    fetched = 0
    inserted = 0
    for symbol in normalized_symbols:
        start_time_ms = storage.latest_spot_trade_time_ms(symbol)
        trades = exchange.my_trades(symbol, start_time_ms=start_time_ms, limit=1000)
        fetched += len(trades)
        for trade in trades:
            if storage.record_spot_trade_fill(symbol, trade):
                inserted += 1

    return SpotTradeSyncResult(
        status="completed",
        reason="spot trade sync completed",
        scanned_symbols=len(normalized_symbols),
        fetched_trades=fetched,
        inserted_trades=inserted,
    )


def _sync_symbols(settings: Settings, symbols: tuple[str, ...] | None) -> tuple[str, ...]:
    raw_symbols = symbols if symbols is not None else (
        *settings.auto_buy_symbols,
        *settings.auto_sell_symbols,
        *settings.ai_trader_symbols,
    )
    seen: set[str] = set()
    normalized: list[str] = []
    for symbol in raw_symbols:
        item = str(symbol).strip().upper()
        if not item or item in seen:
            continue
        seen.add(item)
        normalized.append(item)
    return tuple(normalized)
