"""Orchestrates the full modeling pipeline: ingest → preprocess → fit → optimize → recommend."""

import logging
from dataclasses import asdict, dataclass
from pathlib import Path

import pandas as pd

from mixlift.ingest.service import load_and_parse, save_as_parquet
from mixlift.modeling.engine import ModelResults, run_full_pipeline
from mixlift.modeling.optimizer import optimize_budget
from mixlift.modeling.preprocessing import prepare_model_data
from mixlift.modeling.recommendations import (
    Recommendation,
    format_all_recommendations,
    generate_recommendations,
)

logger = logging.getLogger(__name__)


@dataclass
class PipelineResult:
    """Complete result from the end-to-end pipeline."""

    platform: str
    n_weeks: int
    n_channels: int
    channel_columns: list[str]
    channel_contributions: dict[str, float]
    channel_contributions_ci: dict[str, tuple[float, float]]
    roas_estimates: dict[str, float]
    roas_ci: dict[str, tuple[float, float]]
    current_allocation: dict[str, float]
    optimal_allocation: dict[str, float]
    expected_lift_pct: float
    recommendations: list[Recommendation]
    summary: str
    duration_secs: float


def run_pipeline(
    csv_path: str | Path,
    target_csv_path: str | Path | None = None,
    target_column: str = "revenue",
    platform: str | None = None,
    mcmc_config: dict | None = None,
) -> PipelineResult:
    """Run the complete MixLift pipeline from CSV to recommendations.

    Args:
        csv_path: Path to the marketing data CSV
        target_csv_path: Optional separate CSV with target metric.
                        If None, uses the main CSV (expects a revenue/conversions column).
        target_column: Name of the target column
        platform: Force platform detection (meta, google, tiktok, generic)
        mcmc_config: Optional MCMC overrides

    Returns:
        PipelineResult with all model outputs and recommendations
    """
    logger.info(f"Starting pipeline for {csv_path}")

    # Step 1: Ingest
    canonical, detected_platform = load_and_parse(csv_path, platform)
    logger.info(f"Detected platform: {detected_platform}, {len(canonical)} rows")

    # Step 2: Load target
    target_series = None
    if target_csv_path:
        target_df = pd.read_csv(target_csv_path)
        target_df["date"] = pd.to_datetime(target_df["date"])
        target_series = target_df.set_index("date")[target_column]
    else:
        # Try to find target in the original CSV
        raw_df = pd.read_csv(csv_path)
        if target_column in raw_df.columns:
            raw_df["date"] = pd.to_datetime(raw_df["date"])
            # Aggregate target to weekly
            raw_df["week"] = raw_df["date"].dt.to_period("W-MON").dt.start_time
            weekly_target = raw_df.groupby("week")[target_column].sum()
            weekly_target.index.name = "date"
            target_series = weekly_target

    # Step 3: Preprocess
    X, y, channel_columns = prepare_model_data(canonical, target_series)
    logger.info(f"Model data: {len(X)} weeks, {len(channel_columns)} channels")

    # Step 4: Fit model
    model_results = run_full_pipeline(X, y, channel_columns, mcmc_config)

    # Step 5: Optimize
    opt_results = optimize_budget(model_results.mmm, X, channel_columns)

    # Step 6: Generate recommendations
    recommendations, summary = generate_recommendations(
        current_allocation=opt_results["current_allocation"],
        optimal_allocation=opt_results["optimal_allocation"],
        roas_estimates=model_results.roas_estimates,
        expected_lift_pct=opt_results["expected_lift_pct"],
    )

    return PipelineResult(
        platform=detected_platform,
        n_weeks=len(X),
        n_channels=len(channel_columns),
        channel_columns=channel_columns,
        channel_contributions=model_results.channel_contributions,
        channel_contributions_ci=model_results.channel_contributions_ci,
        roas_estimates=model_results.roas_estimates,
        roas_ci=model_results.roas_ci,
        current_allocation=opt_results["current_allocation"],
        optimal_allocation=opt_results["optimal_allocation"],
        expected_lift_pct=opt_results["expected_lift_pct"],
        recommendations=recommendations,
        summary=summary,
        duration_secs=model_results.duration_secs,
    )
