from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any

import pandas as pd


@dataclass
class ScanConfig:
    """
    Shared scanner configuration for FeatureLeak.

    These defaults are intentionally conservative for v1.
    """

    corr_threshold: float = 0.98
    overlap_threshold: float = 0.0
    id_unique_ratio: float = 0.95
    missingness_target_assoc_threshold: float = 0.30
    adversarial_sample_size: int = 50_000
    max_rows_for_expensive_checks: int = 100_000
    random_state: int = 42


@dataclass
class ScanContext:
    """
    Shared context passed to rules.

    This lets rules avoid repeated argument plumbing and gives them
    access to inferred schema and configuration.
    """

    df: pd.DataFrame
    target: str
    train_df: pd.DataFrame | None = None
    test_df: pd.DataFrame | None = None
    time_col: str | None = None
    entity_cols: list[str] | None = None
    schema: dict[str, Any] = field(default_factory=dict)
    config: ScanConfig = field(default_factory=ScanConfig)

    @property
    def has_train_test(self) -> bool:
        return self.train_df is not None and self.test_df is not None

    @property
    def feature_columns(self) -> list[str]:
        return [col for col in self.df.columns if col != self.target]

    @property
    def n_rows(self) -> int:
        return int(len(self.df))

    @property
    def n_columns(self) -> int:
        return int(len(self.df.columns))