"""Generic CSV parser for any marketing data format."""

import pandas as pd


def parse_generic_csv(df: pd.DataFrame) -> pd.DataFrame:
    """Parse a generic marketing CSV into canonical format.

    Expects columns that can be mapped to: date, channel, spend, impressions, clicks, conversions.
    Falls back to sensible defaults where possible.
    """
    col_map = _find_columns(df)

    result = pd.DataFrame()
    result["date"] = pd.to_datetime(df[col_map["date"]])

    if col_map.get("channel"):
        result["channel"] = df[col_map["channel"]].str.strip()
    else:
        result["channel"] = "Unknown"

    result["spend"] = pd.to_numeric(df[col_map["spend"]], errors="coerce").fillna(0)

    if col_map.get("impressions"):
        result["impressions"] = (
            pd.to_numeric(df[col_map["impressions"]], errors="coerce").fillna(0).astype(int)
        )
    else:
        result["impressions"] = 0

    if col_map.get("clicks"):
        result["clicks"] = (
            pd.to_numeric(df[col_map["clicks"]], errors="coerce").fillna(0).astype(int)
        )
    else:
        result["clicks"] = 0

    if col_map.get("conversions"):
        result["conversions"] = (
            pd.to_numeric(df[col_map["conversions"]], errors="coerce").fillna(0).astype(int)
        )
    else:
        result["conversions"] = 0

    return result


def _find_columns(df: pd.DataFrame) -> dict[str, str]:
    lower_cols = {c.lower().strip(): c for c in df.columns}

    generic_aliases = {
        "date": ["date", "day", "week", "period", "report_date"],
        "channel": ["channel", "campaign", "source", "medium", "platform", "campaign name"],
        "spend": ["spend", "cost", "amount", "ad_spend", "media_spend", "amount spent", "amount spent (usd)"],
        "impressions": ["impressions", "impr", "views"],
        "clicks": ["clicks", "click", "sessions", "visits"],
        "conversions": ["conversions", "conv", "purchases", "orders", "leads", "results"],
    }

    col_map = {}
    for field, aliases in generic_aliases.items():
        for alias in aliases:
            if alias in lower_cols:
                col_map[field] = lower_cols[alias]
                break

    required = ["date", "spend"]
    missing = [f for f in required if f not in col_map]
    if missing:
        raise ValueError(f"CSV missing required columns: {missing}. Found: {list(df.columns)}")

    return col_map
