"""Regime classification — label each bar with the market state it belongs to, CAUSALLY (label[t] uses
only data available at the start of period t, so conditioning return[t] on it has no lookahead).

The first classifier crosses two axes that matter for strategy fit: trend state (price vs its long mean,
in vol-scaled units) × volatility state (recent realized vol vs its own longer baseline). Strategies are
then evaluated *within* each regime — a trend strategy should earn its keep specifically in trend regimes.
"""
from __future__ import annotations

import numpy as np

from fxhnt.domain.models import PriceSeries
from fxhnt.domain.strategies.base import rolling_mean, rolling_std

WARMUP = "warmup"


class VolTrendClassifier:
    name = "vol_trend"

    def __init__(self, trend_window: int = 100, vol_window: int = 20, trend_z: float = 0.5) -> None:
        self.trend_window = trend_window
        self.vol_window = vol_window
        self.trend_z = trend_z

    def classify(self, prices: PriceSeries) -> tuple[str, ...]:
        c = np.asarray(prices.close, float)
        n = len(c)
        if n == 0:
            return ()
        ma = rolling_mean(c, self.trend_window)
        sd = rolling_std(c, self.trend_window)
        z = np.divide(c - ma, sd, out=np.zeros_like(c), where=sd > 0)  # vol-scaled distance from the mean
        logret = np.zeros(n)
        logret[1:] = np.diff(np.log(np.maximum(c, 1e-12)))
        vol = rolling_std(logret, self.vol_window)
        vol_ref = rolling_mean(vol, self.trend_window)  # the instrument's own vol baseline

        labels: list[str] = []
        for t in range(n):
            s = t - 1  # condition on information available at the START of period t (no lookahead)
            if s < self.trend_window:
                labels.append(WARMUP)
                continue
            if z[s] > self.trend_z:
                trend = "trend_up"
            elif z[s] < -self.trend_z:
                trend = "trend_down"
            else:
                trend = "range"
            vol_state = "high_vol" if vol[s] > vol_ref[s] else "low_vol"
            labels.append(f"{trend}|{vol_state}")
        return tuple(labels)
