#!/usr/bin/env python3
"""
Téléchargement massif de données historiques multi-timeframe depuis Binance
"""

import pandas as pd
import requests
import time
from datetime import datetime, timedelta
import logging
import json
from pathlib import Path

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class HistoricalDataDownloader:
    """Télécharge des données historiques massives depuis Binance"""

    def __init__(self):
        self.base_url = "https://api.binance.com/api/v3"
        self.data_dir = Path("historical_data")
        self.data_dir.mkdir(exist_ok=True)

    def download_klines(
        self,
        symbol: str = "BTCUSDT",
        interval: str = "1m",
        days_back: int = 30
    ) -> pd.DataFrame:
        """
        Télécharge les klines sur plusieurs jours

        Args:
            symbol: Symbole du token
            interval: Timeframe (1m, 5m, 15m, 1h, 4h, 1d)
            days_back: Nombre de jours à récupérer

        Returns:
            DataFrame avec toutes les données
        """
        logger.info(f"\n📥 Téléchargement {symbol} - {interval} - {days_back} jours")

        all_data = []

        # Calculer le nombre de bougies par jour pour ce timeframe
        interval_minutes = self._get_interval_minutes(interval)
        candles_per_day = (24 * 60) // interval_minutes
        total_candles_needed = candles_per_day * days_back

        # Binance limite à 1000 bougies par requête
        limit = 1000
        num_requests = (total_candles_needed // limit) + 1

        logger.info(f"   Bougies nécessaires: {total_candles_needed:,}")
        logger.info(f"   Requêtes à faire: {num_requests}")

        # Point de départ: maintenant - days_back jours
        end_time = int(datetime.now().timestamp() * 1000)

        for i in range(num_requests):
            try:
                # Calculer start_time pour cette requête
                start_time = end_time - (limit * interval_minutes * 60 * 1000)

                url = f"{self.base_url}/klines"
                params = {
                    'symbol': symbol,
                    'interval': interval,
                    'limit': limit,
                    'startTime': start_time,
                    'endTime': end_time
                }

                response = requests.get(url, params=params, timeout=30)
                response.raise_for_status()
                data = response.json()

                if not data:
                    break

                all_data.extend(data)

                # Préparer pour la prochaine requête
                end_time = data[0][0] - 1  # Timestamp de la première bougie - 1ms

                if i % 10 == 0:
                    logger.info(f"   Progression: {i+1}/{num_requests} requêtes ({len(all_data):,} bougies)")

                # Rate limiting
                time.sleep(0.1)

            except Exception as e:
                logger.error(f"   Erreur requête {i+1}: {e}")
                break

        # Convertir en DataFrame
        df = self._convert_to_dataframe(all_data)

        logger.info(f"   ✅ {len(df):,} bougies téléchargées")
        logger.info(f"   Période: {df['timestamp'].iloc[0]} → {df['timestamp'].iloc[-1]}")

        return df

    def _get_interval_minutes(self, interval: str) -> int:
        """Convertit l'interval en minutes"""
        mapping = {
            '1m': 1,
            '3m': 3,
            '5m': 5,
            '15m': 15,
            '30m': 30,
            '1h': 60,
            '2h': 120,
            '4h': 240,
            '1d': 1440
        }
        return mapping.get(interval, 1)

    def _convert_to_dataframe(self, data: list) -> pd.DataFrame:
        """Convertit les données Binance en DataFrame"""
        df = pd.DataFrame(data, columns=[
            'timestamp', 'open', 'high', 'low', 'close', 'volume',
            'close_time', 'quote_volume', 'trades', 'taker_buy_base',
            'taker_buy_quote', 'ignore'
        ])

        # Conversion types
        df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
        for col in ['open', 'high', 'low', 'close', 'volume']:
            df[col] = df[col].astype(float)

        # Garder uniquement les colonnes utiles
        df = df[['timestamp', 'open', 'high', 'low', 'close', 'volume']]

        # Trier par timestamp (du plus ancien au plus récent)
        df = df.sort_values('timestamp').reset_index(drop=True)

        return df

    def save_to_file(self, df: pd.DataFrame, symbol: str, interval: str):
        """Sauvegarde les données dans un fichier"""
        filename = self.data_dir / f"{symbol}_{interval}_{len(df)}candles.csv"
        df.to_csv(filename, index=False)
        logger.info(f"   💾 Sauvegardé: {filename} ({len(df):,} bougies)")
        return filename

    def download_all_timeframes(
        self,
        symbol: str = "BTCUSDT",
        timeframes: list = None,
        days_back: int = 30
    ):
        """Télécharge toutes les données pour plusieurs timeframes"""

        if timeframes is None:
            timeframes = ['1m', '5m', '15m']

        logger.info(f"\n{'='*80}")
        logger.info(f"📥 TÉLÉCHARGEMENT MASSIF DE DONNÉES")
        logger.info(f"{'='*80}")
        logger.info(f"Symbol: {symbol}")
        logger.info(f"Timeframes: {', '.join(timeframes)}")
        logger.info(f"Jours: {days_back}")
        logger.info(f"{'='*80}\n")

        results = {}

        for interval in timeframes:
            df = self.download_klines(symbol, interval, days_back)
            filename = self.save_to_file(df, symbol, interval)
            results[interval] = {
                'df': df,
                'filename': filename,
                'candles': len(df),
                'start': df['timestamp'].iloc[0],
                'end': df['timestamp'].iloc[-1]
            }

        logger.info(f"\n{'='*80}")
        logger.info(f"✅ TÉLÉCHARGEMENT TERMINÉ")
        logger.info(f"{'='*80}")

        for interval, info in results.items():
            logger.info(f"\n{interval}:")
            logger.info(f"   Bougies: {info['candles']:,}")
            logger.info(f"   Période: {info['start']} → {info['end']}")
            logger.info(f"   Fichier: {info['filename']}")

        return results


if __name__ == '__main__':
    import sys

    # Paramètres
    symbol = sys.argv[1] if len(sys.argv) > 1 else "BTCUSDT"
    days = int(sys.argv[2]) if len(sys.argv) > 2 else 30

    downloader = HistoricalDataDownloader()

    # Télécharger 1m, 5m, 15m sur X jours
    results = downloader.download_all_timeframes(
        symbol=symbol,
        timeframes=['1m', '5m', '15m'],
        days_back=days
    )

    logger.info(f"\n✅ Toutes les données sont prêtes pour le backtest!")
