import pandas as pd
import numpy as np
import statsmodels.api as sm
from pathlib import Path
import sys

BASE_PATH = Path(__file__).resolve().parents[2]
SRC_PATH = BASE_PATH / "src"

if str(SRC_PATH) not in sys.path:
    sys.path.append(str(SRC_PATH))

from ingestion.price_loader import load_eurusd
from features.yield_spreads import build_spread_features


def build_daily_dataset():
    prices = load_eurusd().copy()

    # Keep EET. Aggregate hourly to daily close.
    daily_px = (
        prices.assign(date=prices["datetime"].dt.normalize())
        .groupby("date", as_index=False)
        .agg(close=("close", "last"))
        .sort_values("date")
        .reset_index(drop=True)
    )

    daily_px["eurusd_return_1d"] = daily_px["close"].pct_change()

    spreads = build_spread_features().copy()

    df = daily_px.merge(
        spreads[
            [
                "date",
                "spread_2y_change_1d",
                "spread_10y_change_1d",
                "spread_2y",
                "spread_10y",
            ]
        ],
        on="date",
        how="inner",
    )

    df = df.dropna().reset_index(drop=True)
    return df


def estimate_rolling_betas(df: pd.DataFrame, window: int = 120):
    df = df.copy()
    beta_2y = np.full(len(df), np.nan)
    beta_10y = np.full(len(df), np.nan)

    for i in range(window, len(df)):
        sample = df.iloc[i - window:i].copy()

        X = sample[["spread_2y_change_1d", "spread_10y_change_1d"]]
        y = sample["eurusd_return_1d"]

        X = sm.add_constant(X)
        model = sm.OLS(y, X).fit()

        beta_2y[i] = model.params.get("spread_2y_change_1d", np.nan)
        beta_10y[i] = model.params.get("spread_10y_change_1d", np.nan)

    df["beta_2y_raw"] = beta_2y
    df["beta_10y_raw"] = beta_10y

    return df


def smooth_clip_and_shift_betas(df: pd.DataFrame, smooth_span: int = 20):
    df = df.copy()

    # Smooth
    df["beta_2y_smooth"] = df["beta_2y_raw"].ewm(span=smooth_span, adjust=False).mean()
    df["beta_10y_smooth"] = df["beta_10y_raw"].ewm(span=smooth_span, adjust=False).mean()

    # Clip to sensible ranges
    df["beta_2y_smooth"] = df["beta_2y_smooth"].clip(lower=-0.10, upper=0.03)
    df["beta_10y_smooth"] = df["beta_10y_smooth"].clip(lower=-0.08, upper=0.05)

    # Shift by 1 day to avoid lookahead
    df["beta_2y"] = df["beta_2y_smooth"].shift(1)
    df["beta_10y"] = df["beta_10y_smooth"].shift(1)

    return df


def build_rolling_beta_model(window: int = 120, smooth_span: int = 20):
    df = build_daily_dataset()
    df = estimate_rolling_betas(df, window=window)
    df = smooth_clip_and_shift_betas(df, smooth_span=smooth_span)

    # Predicted daily FX move from dynamic betas
    df["predicted_return_1d"] = (
        df["beta_2y"] * df["spread_2y_change_1d"] +
        df["beta_10y"] * df["spread_10y_change_1d"]
    )

    model_df = df.dropna(
        subset=[
            "eurusd_return_1d",
            "beta_2y",
            "beta_10y",
            "predicted_return_1d",
        ]
    ).reset_index(drop=True)

    return model_df


if __name__ == "__main__":
    df = build_rolling_beta_model(window=120, smooth_span=20)

    cols = [
        "date",
        "close",
        "eurusd_return_1d",
        "spread_2y_change_1d",
        "spread_10y_change_1d",
        "beta_2y_raw",
        "beta_10y_raw",
        "beta_2y",
        "beta_10y",
        "predicted_return_1d",
    ]

    print(df[cols].head(10))
    print(df[cols].tail(10))

    print("\nRows:", len(df))
    print("Date range:", df["date"].min(), "to", df["date"].max())

    print("\nBeta summary:")
    print(df[["beta_2y", "beta_10y"]].describe())