import pandas as pd

from .classifier import (
    is_dimension_column,
    is_flag_column,
    is_identifier_column,
    is_metric_column,
    is_time_column,
)
from .types import Schema


def infer_schema(df: pd.DataFrame) -> Schema:
    schema = Schema()

    for col in df.columns:
        series = df[col]

        # 1️⃣ Time first
        if is_time_column(series):
            schema.time.append(col)
            continue

        # 2️⃣ Flags
        if is_flag_column(series):
            schema.flags.append(col)
            continue

        # 3️⃣ Identifiers BEFORE metrics (to prevent IDs being seen as metrics)
        if is_identifier_column(series):
            schema.identifiers.append(col)
            continue

        # 4️⃣ Metrics
        if is_metric_column(series):
            schema.metrics.append(col)
            continue

        # 5️⃣ Everything else = dimension
        if is_dimension_column(series):
            schema.dimensions.append(col)

    # Fallback: if no metrics were inferred, use numeric non-time/non-id columns.
    if not schema.metrics:
        excluded = set(schema.time) | set(schema.identifiers) | set(schema.flags)
        for col in df.columns:
            if col in excluded:
                continue
            if pd.api.types.is_numeric_dtype(df[col]):
                schema.metrics.append(col)

    # Fallback: if no time was inferred, parse likely datetime-like object columns.
    if not schema.time:
        for col in df.columns:
            series = df[col]
            if pd.api.types.is_datetime64_any_dtype(series):
                schema.time.append(col)
                break
            if series.dtype == "object":
                parsed = pd.to_datetime(series, errors="coerce")
                if parsed.notna().sum() >= max(3, int(len(series) * 0.6)):
                    schema.time.append(col)
                    break

    return schema
