#!/usr/bin/env python3
"""Generic deterministic quality scoring for market-screening snapshots."""

import math


QUALITY_PROTOCOL_ID = "quality_85_protocol"
QUALITY_TARGET_SCORE = 85
QUALITY_FACTOR_COUNT = 12


def _finite(value, default=None):
    try:
        number = float(value)
    except (TypeError, ValueError):
        return default
    return number if math.isfinite(number) else default


def _between(value, minimum, maximum, *, upper_exclusive=False):
    number = _finite(value)
    if number is None:
        return False
    if upper_exclusive:
        return minimum <= number < maximum
    return minimum <= number <= maximum


def evaluate_quality_features(features, signal=None):
    """Evaluate frozen point-in-time features; never an entry trigger."""
    features = features or {}
    signal = signal or {}
    change_pct = _finite(signal.get("change_pct", features.get("change_pct")))
    intraday_rvol = _finite(signal.get("vol_ratio_intraday", signal.get("vol_ratio", features.get("volume_ratio_intraday"))))
    value_traded = _finite(features.get("value_traded", signal.get("value_traded")))
    rsi = _finite(features.get("rsi_1d", features.get("rsi")))
    adx = _finite(features.get("adx_1d", features.get("adx")))
    di_spread = _finite(features.get("di_spread_1d"))
    vwap_distance = _finite(features.get("vwap_distance_pct"))
    atr_pct = _finite(features.get("atr_pct_1d", features.get("atr_pct")))
    close_position = _finite(features.get("close_position_pct"))
    upper_wick = _finite(features.get("upper_wick_pct"))
    sma20_distance = _finite(features.get("sma20_distance_pct", features.get("sma20_distance")))
    ihsg_regime = str(features.get("ihsg_regime") or "UNKNOWN").upper()
    factors = (
        {"id": "healthy_move", "label": "Kenaikan sehat +1% s/d <12%", "passed": _between(change_pct, 1.0, 12.0, upper_exclusive=True), "value": change_pct},
        {"id": "active_volume", "label": "RVOL intraday ≥1,5x", "passed": intraday_rvol is not None and intraday_rvol >= 1.5, "value": intraday_rvol},
        {"id": "liquidity", "label": "Nilai transaksi ≥Rp2 miliar", "passed": value_traded is not None and value_traded >= 2_000_000_000, "value": value_traded},
        {"id": "healthy_rsi", "label": "RSI 1D 50–68", "passed": _between(rsi, 50.0, 68.0), "value": rsi},
        {"id": "trend_strength", "label": "ADX 1D ≥20", "passed": adx is not None and adx >= 20.0, "value": adx},
        {"id": "buyer_direction", "label": "+DI lebih kuat dari -DI", "passed": di_spread is not None and di_spread > 0, "value": di_spread},
        {"id": "trend_stack", "label": "Harga > SMA20 > SMA50", "passed": features.get("trend_stack_1d") is True, "value": features.get("trend_stack_1d")},
        {"id": "vwap_control", "label": "Di atas VWAP, tidak lebih dari +5%", "passed": _between(vwap_distance, 0.0, 5.0), "value": vwap_distance},
        {"id": "controlled_atr", "label": "ATR 1D 1,5–6%", "passed": _between(atr_pct, 1.5, 6.0), "value": atr_pct},
        {"id": "strong_close", "label": "Close kuat dan upper wick ≤35%", "passed": close_position is not None and close_position >= 60.0 and upper_wick is not None and upper_wick <= 35.0, "value": {"close_position_pct": close_position, "upper_wick_pct": upper_wick}},
        {"id": "market_alignment", "label": "IHSG tidak bearish", "passed": ihsg_regime in {"BULLISH", "NEUTRAL"}, "value": ihsg_regime},
        {"id": "not_extended", "label": "Jarak SMA20 -2% s/d +8%", "passed": _between(sma20_distance, -2.0, 8.0), "value": sma20_distance},
    )
    passed_count = sum(item["passed"] for item in factors)
    score = round(passed_count / QUALITY_FACTOR_COUNT * 100)
    return {
        "id": QUALITY_PROTOCOL_ID,
        "label": "Sukses",
        "score": score,
        "target_score": QUALITY_TARGET_SCORE,
        "passed": score >= QUALITY_TARGET_SCORE,
        "passed_factors": passed_count,
        "factor_count": QUALITY_FACTOR_COUNT,
        "failed_factors": [item["label"] for item in factors if not item["passed"]],
        "factors": list(factors),
        "interpretation": "Skor kualitas screening, bukan winrate dan bukan SIAP ENTRY.",
    }
