"""Headless Python API for MixLift.

Usage:
    from mixlift.api import analyze
    results = analyze("path/to/data.csv")
"""

import json
import logging
import time
from pathlib import Path

import pandas as pd

logger = logging.getLogger(__name__)


def analyze(
    csv_path: str | Path,
    mcmc_config: dict | None = None,
    license_key: str = "",
) -> dict:
    """Run a full Bayesian Marketing Mix Model analysis on a CSV file.

    Args:
        csv_path: Path to a CSV with marketing spend data.
                  Supports wide format (date + spend columns + revenue)
                  and platform exports (Meta, Google, TikTok).
        mcmc_config: Optional MCMC overrides (chains, tune, draws, etc.).
                     Defaults to 2 chains, 500 tune, 250 draws.
        license_key: Optional license key for pro/growth tier limits.

    Returns:
        Dictionary with ROAS estimates, budget optimization, saturation
        analysis, and actionable recommendations.
    """
    from mixlift.ingest.loader import detect_csv_format as _detect_csv_format, load_wide_format as _load_wide_format, load_platform_csv as _load_platform_csv
    from mixlift.modeling.defaults import MCP_CONFIG
    from mixlift.modeling.engine import (
        extract_saturation_curves,
        run_full_pipeline,
    )
    from mixlift.modeling.optimizer import optimize_budget
    from mixlift.modeling.recommendations import generate_recommendations

    csv_path = Path(csv_path)
    if not csv_path.exists():
        return {"status": "error", "message": f"File not found: {csv_path}"}

    t0 = time.time()

    # Load CSV
    try:
        df = pd.read_csv(csv_path)
    except Exception as e:
        return {"status": "error", "message": f"Failed to read CSV: {e}"}

    logger.info(f"Loaded {len(df)} rows from {csv_path}")

    # Detect format and parse
    csv_format = _detect_csv_format(df)
    try:
        if csv_format == "wide":
            X, y, channel_columns = _load_wide_format(df)
        else:
            X, y, channel_columns = _load_platform_csv(df, csv_format)
    except ValueError as e:
        return {"status": "error", "message": str(e)}

    # License validation
    from mixlift_mcp.license import (
        VALIDATE_URL, FREE_MAX_CHANNELS, FREE_MAX_ROWS,
        PRO_MAX_CHANNELS, PRO_MAX_ROWS,
    )
    import httpx as _httpx

    max_channels = FREE_MAX_CHANNELS
    max_rows = FREE_MAX_ROWS
    tier_name = "free"

    if license_key:
        try:
            resp = _httpx.post(
                VALIDATE_URL,
                json={"license_key": license_key},
                timeout=5.0,
            )
            resp.raise_for_status()
            data = resp.json()
            if data.get("valid") and data.get("tier") in ("pro", "growth"):
                max_channels = PRO_MAX_CHANNELS
                max_rows = PRO_MAX_ROWS
                tier_name = data["tier"]
        except Exception:
            logger.warning("License validation failed — falling back to free tier")

    is_paid = tier_name in ("pro", "growth")

    # Usage metering for free tier
    if not is_paid:
        from mixlift_mcp.metering import check_and_increment
        allowed, meter_msg = check_and_increment()
        if not allowed:
            return {"status": "error", "message": meter_msg}
        logger.info(meter_msg)

    n_channels = len(channel_columns)
    n_rows = len(X)

    if n_channels > max_channels:
        return {
            "status": "error",
            "message": (
                f"Dataset has {n_channels} channels but your {tier_name} tier "
                f"allows max {max_channels}. Upgrade at https://mixlift.io/pricing"
            ),
        }
    if n_rows > max_rows:
        return {
            "status": "error",
            "message": (
                f"Dataset has {n_rows:,} rows but your {tier_name} tier "
                f"allows max {max_rows:,}. Upgrade at https://mixlift.io/pricing"
            ),
        }

    # Run modeling
    config = mcmc_config or MCP_CONFIG
    logger.info(f"Running MMM: {len(channel_columns)} channels, {len(X)} rows")
    model_results = run_full_pipeline(X, y, channel_columns, mcmc_config=config)

    # Optimize budget
    optimization = optimize_budget(
        model_results.mmm, X, channel_columns,
        contributions=model_results.raw_contributions,
    )

    # Saturation curves
    saturation_curves = extract_saturation_curves(
        model_results.mmm, X, channel_columns
    )

    # Recommendations
    recommendations, summary = generate_recommendations(
        current_allocation=optimization["current_allocation"],
        optimal_allocation=optimization["optimal_allocation"],
        roas_estimates=model_results.roas_estimates,
        expected_lift_pct=optimization["expected_lift_pct"],
    )

    duration = time.time() - t0
    logger.info(f"Analysis complete in {duration:.1f}s")

    upgrade_msg = "Upgrade to Growth ($299/mo)"

    def _redact_dollars(text: str) -> str:
        import re
        return re.sub(r'\$[\d,]+(?:\.\d+)?(?:/week)?', '$XXX', text)

    return {
        "status": "success",
        "data": {
            "format_detected": csv_format,
            "channels": list(model_results.roas_estimates.keys()),
            "n_channels": len(channel_columns),
            "n_rows": len(X),
        },
        "roas": {
            "estimates": model_results.roas_estimates,
            "confidence_intervals": {
                k: {"low": v[0], "high": v[1]}
                for k, v in model_results.roas_ci.items()
            },
        },
        "channel_contributions": {
            "estimates": model_results.channel_contributions,
        },
        "budget_optimization": {
            "current_allocation": optimization["current_allocation"] if is_paid else upgrade_msg,
            "optimal_allocation": optimization["optimal_allocation"] if is_paid else upgrade_msg,
            "total_budget": optimization["total_budget"] if is_paid else upgrade_msg,
            "expected_lift_pct": optimization["expected_lift_pct"],
        },
        "recommendations": {
            "summary": summary if is_paid else _redact_dollars(summary),
            "actions": [
                {
                    "rank": r.rank,
                    "action": r.action,
                    "channel": r.channel,
                    "change_amount": r.change_amount if is_paid else upgrade_msg,
                    "current_spend": r.current_spend if is_paid else upgrade_msg,
                    "optimal_spend": r.optimal_spend if is_paid else upgrade_msg,
                    "roas": r.roas,
                    "reason": r.reason if is_paid else _redact_dollars(r.reason),
                }
                for r in recommendations
            ],
        },
        "saturation_curves": saturation_curves,
        "marginal_roas": {
            "estimates": model_results.marginal_roas_estimates,
        },
        "diagnostics": {
            "convergence_warnings": model_results.convergence_warnings,
        },
        "model_info": {
            "duration_secs": round(duration, 1),
            "total_spend": model_results.total_spend if is_paid else upgrade_msg,
        },
    }
