from typing import Dict
import pandas as pd
import warnings

from quickml.decisions import Decision, DecisionLog


class SchemaInferer:
    def __init__(self, log: DecisionLog, strict: bool = False):
        self.log = log
        self.strict = strict

    def infer(self, df: pd.DataFrame) -> Dict[str, str]:
        schema = {}

        for column in df.columns:
            dtype = df[column].dtype

            # Numeric
            if pd.api.types.is_numeric_dtype(dtype):
                schema[column] = "numeric"
                self.log.add(
                    Decision.create(
                        category="schema",
                        component="SchemaInferer",
                        action="infer_numeric",
                        reason=f"Column dtype is {dtype}",
                        parameters={"column": column},
                        impact="Used for numeric preprocessing",
                        severity="info",
                    )
                )

            # Datetime
            elif pd.api.types.is_datetime64_any_dtype(dtype):
                schema[column] = "datetime"
                self.log.add(
                    Decision.create(
                        category="schema",
                        component="SchemaInferer",
                        action="infer_datetime",
                        reason="Column dtype is datetime",
                        parameters={"column": column},
                        impact="Datetime feature extraction",
                        severity="info",
                    )
                )

            # Object
            else:
                schema[column] = self._infer_object_column(df, column)

        return schema

    def _infer_object_column(self, df: pd.DataFrame, column: str) -> str:
        series = df[column]

        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")

            try:
                pd.to_datetime(series, errors="raise")

                # Log datetime inference
                self.log.add(
                    Decision.create(
                        category="schema",
                        component="SchemaInferer",
                        action="infer_datetime_from_object",
                        reason="Object column successfully parsed as datetime",
                        parameters={"column": column},
                        impact="Datetime feature extraction",
                        severity="warning",
                    )
                )

                # Log pandas warning explicitly
                if w:
                    self.log.add(
                        Decision.create(
                            category="schema",
                            component="SchemaInferer",
                            action="datetime_inference_warning",
                            reason=str(w[0].message),
                            parameters={"column": column},
                            impact="Datetime parsed with fallback parser",
                            severity="warning",
                        )
                    )

                return "datetime"

            except Exception:
                pass

        # Default categorical
        self.log.add(
            Decision.create(
                category="schema",
                component="SchemaInferer",
                action="infer_categorical",
                reason="Object dtype not parseable as datetime",
                parameters={"column": column},
                impact="Used for categorical preprocessing",
                severity="info",
            )
        )

        return "categorical"
