import numpy as np
import pandas as pd
import logging
from scipy.stats import skew
from .audit import AuditTrail

logger = logging.getLogger("Scout")

class Scout:
    def __init__(self, audit, target_col, threshold=0.95):
        self.audit = audit
        self.target_col = target_col
        self.threshold = threshold
        self.problem_type = None
        self.numeric_cols = []
        self.categorical_cols = []
        self.dropped_cols = []
        self.cardinality_map = {}

    def analyze(self, df):
        # --- FIX 1: REMOVER COLUNAS DUPLICADAS DO DATAFRAME ---
        # Isso evita que a mesma coluna seja processada duas vezes
        df = df.loc[:, ~df.columns.duplicated()]
        # -----------------------------------------------------
        
        self._infer_type(df)
        self._stats(df)
        if self.problem_type != "regression": self._imb(df)
        self._quality(df)
        self._classify(df)
        self._leakage(df)
        return self

    def _infer_type(self, df):
        y = df[self.target_col]
        if pd.api.types.is_numeric_dtype(y) and y.nunique() > 20: self.problem_type = "regression"
        else: self.problem_type = "binary" if y.nunique() == 2 else "multiclass"

    def _stats(self, df):
        stats = []
        num = df.select_dtypes(include=np.number)
        for c in num.columns:
            if c == self.target_col: continue
            s = num[c].dropna()
            if len(s)==0: continue
            
            q1, q3 = s.quantile(0.25), s.quantile(0.75)
            out = ((s < (q1-1.5*(q3-q1))) | (s > (q3+1.5*(q3-q1)))).mean()
            sk = skew(s)
            
            rec = "StandardScaler"
            if out > 0.05: rec = "RobustScaler"
            elif abs(sk) > 1.0: rec = "PowerTransformer"
            stats.append({"column": c, "outliers": out, "skew": sk, "recommendation": rec})
        
        if stats: self.audit.register_feature_stats(pd.DataFrame(stats))

    def _quality(self, df):
        nulls = df.isnull().mean()
        self.dropped_cols.extend(nulls[nulls > 0.95].index.tolist())
        for c in df.columns:
            if df[c].nunique() <= 1: self.dropped_cols.append(c)

    def _classify(self, df):
        valid = [c for c in df.columns if c != self.target_col and c not in self.dropped_cols]
        for c in valid:
            if pd.api.types.is_numeric_dtype(df[c]): self.numeric_cols.append(c)
            else: 
                self.categorical_cols.append(c)
                self.cardinality_map[c] = df[c].nunique()
            
            if df[c].nunique() / len(df) > 0.98 and not pd.api.types.is_numeric_dtype(df[c]):
                self.dropped_cols.append(c)

    def _leakage(self, df):
        logger.info("Checking Leakage...")
        X = df.drop(columns=[self.target_col] + self.dropped_cols, errors='ignore')
        y = df[self.target_col]
        if self.problem_type != "regression" and not pd.api.types.is_numeric_dtype(y):
            y = y.astype("category").cat.codes

        data = {}
        cols = []
        for c in X.select_dtypes(include=np.number).columns:
            data[c] = X[c].fillna(0).values; cols.append(c)
        for c in X.select_dtypes(exclude=np.number).columns:
            data[c] = X[c].astype("category").cat.codes.values; cols.append(c)
            
        X_enc = pd.DataFrame(data, index=X.index)
        
        from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor
        from sklearn.model_selection import cross_val_score
        
        model = DecisionTreeRegressor(max_depth=1) if self.problem_type == "regression" else DecisionTreeClassifier(max_depth=1)
        
        for c in cols:
            try:
                if cross_val_score(model, X_enc[[c]], y, cv=3).mean() > self.threshold:
                    self.dropped_cols.append(c)
                    self.audit.log_action("Scout", f"Leakage: {c}")
            except: pass

    def _imb(self, df):
        if df[self.target_col].value_counts(normalize=True).min() < 0.10: self.is_imbalanced = True
    
    def optimize_memory(self, df):
        # Protege contra duplicatas ao otimizar também
        df = df.loc[:, ~df.columns.duplicated()]
        for c in df.select_dtypes(include="float64").columns: df[c] = df[c].astype("float32")
        return df
