import pandas as pd
import numpy as np
from typing import Optional, Union, List

class DataValidator:
    """
    Validator for input data quality and consistency checks.
    """
    
    def __init__(self):
        pass

    def validate(self, X: pd.DataFrame, y: Union[pd.Series, np.ndarray, str], 
                 date_col: Optional[str] = None) -> bool:
        """
        Validate input data for modeling.
        
        Parameters:
        -----------
        X : pd.DataFrame
            Feature matrix
        y : pd.Series or str
            Target variable or column name in X
        date_col : str, optional
            Date column name
            
        Returns:
        --------
        bool
            True if validation passes
            
        Raises:
        -------
        ValueError
            If validation fails
        """
        print("Validating input data...")
        
        # 1. Check X type
        if not isinstance(X, pd.DataFrame):
            raise ValueError("X must be a pandas DataFrame")
            
        if X.empty:
            raise ValueError("Input DataFrame X is empty")
            
        # 2. Check y
        y_series = None
        if isinstance(y, str):
            if y not in X.columns:
                raise ValueError(f"Target column '{y}' not found in X")
            y_series = X[y]
        elif isinstance(y, (pd.Series, np.ndarray, list)):
            y_series = pd.Series(y)
            if len(y_series) != len(X):
                raise ValueError(f"Target length ({len(y_series)}) does not match X length ({len(X)})")
        else:
            raise ValueError("y must be a Series, numpy array, list, or column name string")
            
        # 3. Check target distribution (Binary)
        # Drop NaNs from target check
        y_clean = y_series.dropna()
        unique_vals = np.unique(y_clean)
        
        # Check if empty after dropping NaNs
        if len(y_clean) == 0:
            raise ValueError("Target variable contains only NaN values")
            
        # Check for binary classification
        if len(unique_vals) > 2:
            print(f"Warning: Target variable appears to have more than 2 classes: {unique_vals[:5]}...")
            print("AutoScore is optimized for binary classification (0/1).")
        
        # Check if values are 0 and 1
        if not set(unique_vals).issubset({0, 1, 0.0, 1.0}):
            print(f"Warning: Target variable values are {unique_vals}. Expected {{0, 1}}.")
            
        # 4. Check date_col
        if date_col:
            if date_col not in X.columns:
                print(f"Warning: Date column '{date_col}' not found in X.")
            else:
                # Check if date column is empty
                if X[date_col].isnull().all():
                    print(f"Warning: Date column '{date_col}' is entirely None/NaN.")
                    
        # 5. Check for high missing rate in features (Warning only)
        missing_series = X.isnull().mean()
        high_missing_cols = missing_series[missing_series > 0.95].index.tolist()
        if high_missing_cols:
            print(f"Warning: {len(high_missing_cols)} features have >95% missing values.")
            
        print("Data validation completed.")
        return True
