"""Quantile target model for price-delta forecasts."""

import os
import re
from pathlib import Path

import joblib
import numpy as np

from ..training.train_direction import ALL_FEATURE_KEYS

MODEL_DIR = Path(os.getenv("MODEL_DIR", "models"))


def _horizon_to_minutes(horizon: str) -> float:
    value = str(horizon or "4h").strip().lower()
    total = 0.0
    for amount, unit in re.findall(r"(\d+)(mo|y|w|d|h|m)", value):
        quantity = float(amount or 0)
        if unit == "m":
            total += quantity
        elif unit == "h":
            total += quantity * 60
        elif unit == "d":
            total += quantity * 1440
        elif unit == "w":
            total += quantity * 10080
        elif unit == "mo":
            total += quantity * 43200
        elif unit == "y":
            total += quantity * 525600
    return total if total > 0 else 240.0


class TargetQuantileModel:
    FEATURE_KEYS = ALL_FEATURE_KEYS + ["probability_hint", "horizon_minutes"]

    def __init__(self) -> None:
        self.version = "0.1.0"
        self.is_loaded = False
        self.last_trained: str | None = None
        self.accuracy: float | None = None
        self.models: dict[str, object] = {}

    def load(self) -> None:
        path = MODEL_DIR / "target_xgb_quantile.joblib"
        try:
            data = joblib.load(path)
            self.models = data.get("models", {})
            self.last_trained = data.get("trained_at")
            self.accuracy = data.get("accuracy")
            self.is_loaded = True
        except Exception:
            self.models = {}
            self.is_loaded = True

    def predict(self, features: dict) -> dict:
        if self.models:
            return self._predict_model(features)
        return self._predict_heuristic(features)

    def _predict_model(self, features: dict) -> dict:
        enriched = dict(features)
        enriched["probability_hint"] = float(features.get("probability_hint", 0.5))
        enriched["horizon_minutes"] = _horizon_to_minutes(str(features.get("horizon", "4h")))
        x = np.array([[enriched.get(k, 0.0) for k in self.FEATURE_KEYS]], dtype=np.float32)
        q10 = float(self.models["q10"].predict(x)[0])
        q50 = float(self.models["q50"].predict(x)[0])
        q90 = float(self.models["q90"].predict(x)[0])
        low, base, high = sorted([q10, q50, q90])
        return {
            "low_change_pct": round(low, 4),
            "base_change_pct": round(base, 4),
            "high_change_pct": round(high, 4),
            "direction_bias": "up" if base > 0.1 else "down" if base < -0.1 else "sideways",
            "interval_width_pct": round(high - low, 4),
            "model": "target_xgb_quantile",
        }

    def _predict_heuristic(self, features: dict) -> dict:
        base = (
            float(features.get("emaCrossoverPct", 0.0)) * 0.35
            + float(features.get("macdHistogram", 0.0)) * 2.0
            + float(features.get("rsiSlope", 0.0)) * 0.08
        )
        width = max(0.35, float(features.get("atrPct", 0.5)) * 1.4)
        low = base - width
        high = base + width
        return {
            "low_change_pct": round(low, 4),
            "base_change_pct": round(base, 4),
            "high_change_pct": round(high, 4),
            "direction_bias": "up" if base > 0.1 else "down" if base < -0.1 else "sideways",
            "interval_width_pct": round(high - low, 4),
            "model": "heuristic-target-quantile",
        }
