import pandas as pd
import numpy as np
from typing import Dict, Any


class FactorAnalyzer:
    """Minimal single-factor analyzer for quick sanity checks."""

    def basic_profile(self, series: pd.Series) -> Dict[str, Any]:
        s = series.dropna()
        return {
            "count": float(len(s)),
            "missing_ratio": float(1 - len(s) / len(series)) if len(series) else float("nan"),
            "mean": float(s.mean()) if len(s) else float("nan"),
            "std": float(s.std()) if len(s) else float("nan"),
            "skew": float(s.skew()) if len(s) else float("nan"),
            "kurt": float(s.kurt()) if len(s) else float("nan"),
            "min": float(s.min()) if len(s) else float("nan"),
            "p25": float(s.quantile(0.25)) if len(s) else float("nan"),
            "median": float(s.median()) if len(s) else float("nan"),
            "p75": float(s.quantile(0.75)) if len(s) else float("nan"),
            "max": float(s.max()) if len(s) else float("nan"),
        }

    def top_bottom_spread(self, series: pd.Series, quantile: float = 0.2) -> Dict[str, Any]:
        s = series.dropna()
        if not len(s):
            return {"top_mean": float("nan"), "bottom_mean": float("nan"), "spread": float("nan")}
        q = np.clip(quantile, 0.0, 0.5)
        bottom = s[s <= s.quantile(q)]
        top = s[s >= s.quantile(1 - q)]
        top_mean = float(top.mean()) if len(top) else float("nan")
        bottom_mean = float(bottom.mean()) if len(bottom) else float("nan")
        return {
            "top_mean": top_mean,
            "bottom_mean": bottom_mean,
            "spread": float(top_mean - bottom_mean) if np.isfinite(top_mean) and np.isfinite(bottom_mean) else float("nan"),
        }

    def analyze(self, series: pd.Series, quantile: float = 0.2) -> Dict[str, Any]:
        return {
            "basic": self.basic_profile(series),
            "top_bottom": self.top_bottom_spread(series, quantile=quantile),
        }
