from dataclasses import dataclass, field
from typing import List, Dict, Optional, Union, Any
import numpy as np
import sklearn

SKLEARN_VERSION = tuple(map(int, sklearn.__version__.split('.')[:2]))
SGD_LOSS_COMPAT = 'log_loss' if SKLEARN_VERSION >= (1, 1) else 'log'

@dataclass
class DataConfig:
    """Configuration for data processing and splitting."""
    test_size: float = 0.3
    date_col: str = 'create_time'
    oot_split_date: Optional[str] = None
    target_col: str = 'target'
    exclude_cols: List[str] = field(default_factory=list)
    excluded_features: List[str] = field(default_factory=list)
    special_values: List[Union[int, float]] = field(default_factory=list)
    protected_features: List[str] = field(default_factory=list)

@dataclass
class BinningConfig:
    """Configuration for binning process."""
    max_bins: int = 10
    min_bin_pct: float = 0.05
    monotonicity_constraints: Optional[Dict[str, int]] = None
    custom_binning_rules: Optional[Dict] = None
    final_bins: Optional[Dict] = None

@dataclass
class SelectionConfig:
    """Configuration for feature selection."""
    iv_threshold: float = 0.02
    missing_threshold: float = 0.95
    single_value_threshold: float = 0.99
    vif_threshold: float = 10.0
    corr_threshold: float = 0.8
    selection_method: str = 'backward_lr'
    auc_threshold_decrease: float = 0.005
    final_features: Optional[List[str]] = None

@dataclass
class ModelConfig:
    """Configuration for model training and scorecard generation."""
    pdo: int = 20
    base_score: int = 600
    base_odds: int = 50
    random_state: int = 42

class Config:
    RANDOM_STATE = 42
    
    MISSING_VALUES = [float('nan'), None, np.nan]
    
    SPECIAL_VALUES = []
    
    MAX_BINS = 10
    MIN_BIN_PCT = 0.05
    
    IV_THRESHOLD = 0.02
    PSI_THRESHOLD = 0.1
    CORR_THRESHOLD = 0.7
    
    TEST_SIZE = 0.3
    
    SGD_ALPHA = 0.0001
    SGD_LEARNING_RATE = 'adaptive'
    SGD_ETA0 = 0.01
    SGD_MAX_ITER = 1000
    SGD_PENALTY = 'l2'
    SGD_LOSS = SGD_LOSS_COMPAT
