"""
Единый реестр признаков для ML-моделей.

Цель: ликвидировать 5+ копий get_directional_feature_cols, разбросанных по проекту.
Использовать как единственный источник истины для списка колонок.
"""

from features.technical import (FEATURE_COLS, INTERACTION_COLS, TEMPORAL_COLS,
                                HURST_COLS, VWAP_COLS)
from features.directional import DIRECTIONAL_COLS, SHORT_SPECIFIC_COLS
from features.context import CONTEXT_COLS
from features.mtf_context import MTF_CONTEXT_COLS

# ──────────────────────────────────────────────────────────
# Дополнительные признаки, добавленные в v12.8 (feature selection)
# Высокоинформативные, были только в df, не входили в base features
# ──────────────────────────────────────────────────────────
EXTRA_FEATURE_COLS = [
    'adx', 'pdi', 'mdi',                     # ADX trend strength
    'rv_5', 'rv_10', 'rv_20',                # Realized volatility
    'parkinson_vol', 'garman_klass_vol', 'yang_zhang_vol',  # Vol estimators
    # v13 features (audit 2026-08-03):
    'hurst_100', 'is_trending', 'is_mean_reverting', 'hurst_confidence',  # Hurst exponent regime
    'vwap_24', 'vwap_dist_pct', 'above_vwap',         # VWAP distance
]

# ──────────────────────────────────────────────────────────
# Dead features (zero importance в BOTH Long и Short XGBoost)
# Удалены из основного списка, но оставлены для анализа
# ──────────────────────────────────────────────────────────
DEAD_FEATURES = {
    'short_div_signal', 'short_vol_climax', 'short_fail_break', 'long_vol_climax',  # SHORT_SPECIFIC
    'doji', 'hh_streak', 'll_streak',                                                # CONTEXT
    'is_main_session', 'is_evening_session', 'is_market_open', 'session_hour',       # TEMPORAL
}

# ──────────────────────────────────────────────────────────
# Borderline features (важность < 0.003 в обоих моделях)
# Удаляются только при strict=True
# ──────────────────────────────────────────────────────────
BORDERLINE_FEATURES = {
    'volume_ratio',
    'rsi_signal_accel', 'directional_bias_accel',
    'hour_sin', 'hour_cos', 'dow_sin',
    'engulfing',
}


def get_directional_cols(multi: bool = False) -> list[str]:
    """
    Возвращает полный список признаков, используемых в моделях.

    Порядок: directional → short_specific → technical → context → interactions → temporal → mtf.
    Дубликаты удаляются с сохранением порядка (dict.fromkeys).

    Args:
        multi: Если True — добавляются префиксные копии DIRECTIONAL_COLS + FEATURE_COLS для D1/W1.

    Returns:
        Список имён колонок (без дубликатов).
    """
    cols = list(dict.fromkeys(
        DIRECTIONAL_COLS + SHORT_SPECIFIC_COLS + FEATURE_COLS + CONTEXT_COLS
        + INTERACTION_COLS + TEMPORAL_COLS + MTF_CONTEXT_COLS
    ))
    if multi:
        multi_cols = list(dict.fromkeys(DIRECTIONAL_COLS + FEATURE_COLS))
        cols += [f'{tf}_{col}' for tf in ['D1', 'W1'] for col in multi_cols]
    return list(dict.fromkeys(cols))


def clean_base_features(strict: bool = False) -> list[str]:
    """
    Возвращает оптимизированный список базовых признаков для MoE v12.8+.
    
    Отличия от get_directional_cols():
    - Удалены dead-фичи (zero importance в Long/Short XGBoost)
    - Удалён rsi_signal (дублирует rsi с r=1.0)
    - Добавлены ADX + волатильностные метрики (высокоинформативны)
    
    Args:
        strict: Если True, дополнительно удаляет borderline-фичи
                (очень низкая важность < 0.003 в обеих моделях).
    
    Returns:
        Список базовых признаков (без дубликатов).
    """
    # Технические фичи + новые ADX/Vol метрики
    tech = FEATURE_COLS + EXTRA_FEATURE_COLS
    
    # Directional — без rsi_signal (дублирует rsi)
    directional = [c for c in DIRECTIONAL_COLS if c != 'rsi_signal']
    
    # Short-specific — без dead
    short_sp = [c for c in SHORT_SPECIFIC_COLS if c not in DEAD_FEATURES]
    
    # Context — без dead
    ctx = [c for c in CONTEXT_COLS if c not in DEAD_FEATURES]
    
    # Temporal — без dead
    temporal = [c for c in TEMPORAL_COLS if c not in DEAD_FEATURES]
    if strict:
        temporal = [c for c in temporal if c not in BORDERLINE_FEATURES]
    
    cols = list(dict.fromkeys(
        tech + directional + short_sp + ctx + INTERACTION_COLS + temporal + MTF_CONTEXT_COLS
    ))
    
    if strict:
        cols = [c for c in cols if c not in BORDERLINE_FEATURES]
    
    return cols


def validate_feature_cols(cols: list[str]) -> list[str]:
    """
    Проверяет список признаков на дубликаты и возвращает его.
    Выбрасывает ValueError при обнаружении дубликатов (не отключается при python -O).
    """
    if len(cols) != len(set(cols)):
        duplicates = [c for c in cols if cols.count(c) > 1]
        raise ValueError(
            f"Дубликаты в признаках: {len(cols)} vs {len(set(cols))}. "
            f"Повторяющиеся: {sorted(set(duplicates))}"
        )
    return cols
