"""
XGBoost model wrapper for candlestick pattern classification.

Provides a wrapper around XGBoost's XGBClassifier with support for
class weight balancing.
"""

from typing import Any, Dict, Optional

import numpy as np
from xgboost import XGBClassifier
from sklearn.utils.class_weight import compute_class_weight


class XGBoostModel:
    """
    XGBoost classifier wrapper for candlestick patterns.
    
    Attributes:
        model: The underlying XGBClassifier instance
        classes_: Fitted class labels
        feature_importances_: Feature importance scores (after fitting)
    """
    
    def __init__(self, hyperparameters: Dict[str, Any], class_weights: Optional[str] = None):
        """
        Initialize XGBoost model.
        
        Args:
            hyperparameters: Model hyperparameters from config
            class_weights: "balanced" for inverse-frequency weighting, None for no weighting
        """
        self.hyperparameters = hyperparameters.copy()
        self.class_weights = class_weights
        self._sample_weights = None
        
        # XGBoost doesn't have built-in class_weight parameter like sklearn
        # We'll compute sample weights manually when class_weights is "balanced"
        
        # Initialize XGBoost model
        self.model = XGBClassifier(**self.hyperparameters)
        
    def fit(self, X: np.ndarray, y: np.ndarray):
        """
        Train the XGBoost model.
        
        Args:
            X: Training features (n_samples, n_features)
            y: Training labels (n_samples,)
            
        Returns:
            self
        """
        # Compute sample weights if class weighting is enabled
        if self.class_weights == "balanced":
            # Compute class weights
            classes = np.unique(y)
            class_weights = compute_class_weight(
                class_weight="balanced",
                classes=classes,
                y=y
            )
            
            # Map class weights to sample weights
            class_weight_dict = dict(zip(classes, class_weights))
            sample_weights = np.array([class_weight_dict[label] for label in y])
            
            # Fit with sample weights
            self.model.fit(X, y, sample_weight=sample_weights)
        else:
            # Fit without sample weights
            self.model.fit(X, y)
        
        return self
    
    def predict(self, X: np.ndarray) -> np.ndarray:
        """
        Predict class labels.
        
        Args:
            X: Features (n_samples, n_features)
            
        Returns:
            Predicted labels (n_samples,)
        """
        return self.model.predict(X)
    
    def predict_proba(self, X: np.ndarray) -> np.ndarray:
        """
        Predict class probabilities.
        
        Args:
            X: Features (n_samples, n_features)
            
        Returns:
            Class probabilities (n_samples, n_classes)
        """
        return self.model.predict_proba(X)
    
    @property
    def classes_(self):
        """Get fitted class labels."""
        return self.model.classes_
    
    @property
    def feature_importances_(self):
        """Get feature importance scores."""
        return self.model.feature_importances_
    
    def get_params(self) -> Dict[str, Any]:
        """
        Get model parameters.
        
        Returns:
            Dictionary of model hyperparameters
        """
        return self.model.get_params()
    
    def __repr__(self):
        return f"XGBoostModel(n_estimators={self.hyperparameters.get('n_estimators', 100)})"
