from __future__ import annotations

from typing import List, Tuple

import pandas as pd
from loguru import logger

from db import fetch_ohlcv, fetch_ohlcv_last_bars


class DataPreparator:
    def __init__(self, tickers: List[str], timeframes: List[str] = None):
        self.tickers = tickers
        self.timeframes = timeframes or ["H1"]
        self.cache = {}

    _MIN_BARS = {"D1": 60, "H1": 200, "H4": 60, "M30": 200, "M15": 200, "M5": 200}
    _MIN_BARS_DEFAULT = 100

    def load_h1(self, ticker: str, start_ts: int, end_ts: int) -> pd.DataFrame:
        """Load H1 data for a ticker with auto-expansion if range is empty or too short."""
        return self._load_reliable(ticker, "H1", start_ts, end_ts)

    def _load_reliable(self, ticker: str, tf: str, start_ts: int, end_ts: int) -> pd.DataFrame:
        """Load data expanding range automatically if needed to get enough bars."""
        min_bars = self._MIN_BARS.get(tf, self._MIN_BARS_DEFAULT)
        df = fetch_ohlcv(ticker, tf, start_ts, end_ts)

        if not df.empty and len(df) >= min_bars:
            return df

        for expand_hours in [720, 1680, 3360]:
            expanded_start = start_ts - (expand_hours * 3600)
            df = fetch_ohlcv(ticker, tf, expanded_start, end_ts + 3600)
            if not df.empty:
                if len(df) >= min_bars:
                    logger.debug(f"{ticker}_{tf}: expanded range, got {len(df)} bars")
                    return df
                logger.debug(f"{ticker}_{tf}: expanded range but only {len(df)} bars, trying fallback")
        logger.debug(f"{ticker}_{tf}: fetching last {min_bars} bars (ignore time range)")
        df = fetch_ohlcv_last_bars(ticker, tf, min_bars)
        if not df.empty:
            return df

        return pd.DataFrame()
