#!/usr/bin/env python3
"""
Generate realistic historical OHLCV data for XAUUSD (Gold vs USD)
Saves data as parquet files in the live store format for testing.
"""

import os
import random
import math
from datetime import datetime, timedelta
from typing import List, Dict, Any
import pyarrow as pa
import pyarrow.parquet as pq


def generate_gold_prices(start_date: datetime, end_date: datetime, base_price: float = 2000.0) -> List[Dict[str, Any]]:
    """
    Generate realistic 1-minute OHLCV data for gold prices.

    Gold price characteristics:
    - Base price around $2000/oz
    - Daily volatility ~0.5-1.5%
    - Higher volatility during market hours (London/New York overlap)
    - Weekend gaps
    - Trend following with mean reversion
    """

    data = []
    current_price = base_price
    trend = 0.0  # Trend direction (-1 to 1)
    volatility = 0.008  # Base volatility (0.8%)

    current = start_date
    while current <= end_date:
        # Skip weekends (Saturday=5, Sunday=6)
        if current.weekday() >= 5:
            current += timedelta(minutes=1)
            continue

        # Market hours: 00:00-23:59 UTC (24/7 for forex, but lower volume on weekends)
        hour = current.hour

        # Adjust volatility based on market session
        # London: 08:00-16:00 UTC, New York: 14:30-21:00 UTC
        # Overlap (high volume): 14:30-16:00 UTC
        if 14 <= hour < 16:
            session_volatility = volatility * 1.5  # Higher volatility during overlap
        elif 8 <= hour < 21:
            session_volatility = volatility * 1.2  # Active session
        else:
            session_volatility = volatility * 0.7  # Low volume

        # Random walk with trend and mean reversion
        trend_change = random.gauss(0, 0.001)  # Slow trend changes
        trend = max(-0.5, min(0.5, trend + trend_change))

        # Mean reversion to base price
        reversion = (base_price - current_price) / base_price * 0.001

        # Price change
        price_change_pct = random.gauss(trend * 0.0001 + reversion, session_volatility)
        price_change = current_price * price_change_pct
        new_price = current_price + price_change

        # Ensure reasonable bounds
        new_price = max(1500, min(3000, new_price))

        # Generate OHLC for 1-minute candle
        high = new_price + abs(random.gauss(0, new_price * session_volatility * 0.5))
        low = new_price - abs(random.gauss(0, new_price * session_volatility * 0.5))
        open_price = current_price + random.gauss(0, new_price * session_volatility * 0.3)
        close_price = new_price

        # Ensure OHLC relationships
        high = max(high, open_price, close_price)
        low = min(low, open_price, close_price)

        # Volume (simulated, higher during active hours)
        base_volume = random.randint(50, 200)
        if 14 <= hour < 16:
            volume = int(base_volume * 2.5)
        elif 8 <= hour < 21:
            volume = int(base_volume * 1.8)
        else:
            volume = base_volume

        bar = {
            "time": int(current.timestamp()),
            "open": round(open_price, 2),
            "high": round(high, 2),
            "low": round(low, 2),
            "close": round(close_price, 2),
            "volume": volume
        }

        data.append(bar)
        current_price = close_price
        current += timedelta(minutes=1)

    return data


def save_to_parquet(data: List[Dict[str, Any]], symbol: str, timeframe: str, base_dir: str = "data/parquet/live"):
    """Save OHLCV data to parquet files partitioned by date."""

    # Group by date
    from collections import defaultdict
    data_by_date = defaultdict(list)

    for bar in data:
        dt = datetime.utcfromtimestamp(bar["time"])
        date_str = dt.strftime("%Y-%m-%d")
        data_by_date[date_str].append(bar)

    # Save each date partition
    for date_str, bars in data_by_date.items():
        # Sort by time
        bars.sort(key=lambda x: x["time"])

        # Create directory
        partition_dir = os.path.join(base_dir, symbol, timeframe, f"date={date_str}")
        os.makedirs(partition_dir, exist_ok=True)

        # Convert to pyarrow table
        table = pa.Table.from_pylist(bars)

        # Save as parquet
        file_path = os.path.join(partition_dir, f"historical-{int(datetime.utcnow().timestamp())}.parquet")
        pq.write_table(table, file_path)
        print(f"Saved {len(bars)} bars for {date_str} to {file_path}")


def main():
    """Generate 3 months of historical data."""

    # Generate data for the last 90 days
    end_date = datetime.utcnow()
    start_date = end_date - timedelta(days=90)

    print(f"Generating historical data from {start_date.date()} to {end_date.date()}")

    # Generate data
    data = generate_gold_prices(start_date, end_date)

    print(f"Generated {len(data)} 1-minute bars")

    # Save to parquet
    save_to_parquet(data, "XAUUSD", "1m")

    print("Historical data generation complete!")


if __name__ == "__main__":
    main()