"""Cohort (campaign) management tools for Influ2 MCP."""

from __future__ import annotations

import asyncio
import json
from typing import Annotated, Any

from influ2_mcp.client import get_api_client
from influ2_mcp.config import resolve_client_id
from influ2_mcp.errors import (
    Influ2Error,
    format_error_for_llm,
)
from influ2_mcp.server import mcp


def _strip_targets_from_response(data: Any) -> None:
    """Remove large target arrays from API responses to stay under MCP's 1MB limit.

    Replaces targets with a count and small sample. Mutates data in-place.
    Works on nested dicts (cohort responses, job results, etc.).
    """
    if not isinstance(data, dict):
        return

    # Strip top-level targets
    if "targets" in data and isinstance(data["targets"], list):
        targets = data.pop("targets")
        data["target_count"] = len(targets)
        if targets:
            data["target_sample"] = targets[:3]

    # Recurse into nested dicts (e.g., job results wrapping cohort data)
    for value in data.values():
        if isinstance(value, dict):
            _strip_targets_from_response(value)
        elif isinstance(value, list):
            for item in value:
                if isinstance(item, dict):
                    _strip_targets_from_response(item)


@mcp.tool()
async def influ2_list_cohorts(
    client_id: Annotated[
        str | None,
        "Influ2 client ID. Omit to use the configured default (INFLU2_CLIENT_ID).",
    ] = None,
    status: Annotated[
        str | None,
        "Filter by status: 'active' or 'archived'. Omit for all cohorts.",
    ] = None,
    limit: Annotated[int, "Max results to return (1-100, default 50)"] = 50,
    offset: Annotated[int, "Pagination offset (default 0)"] = 0,
) -> str:
    """List cohort bundles (campaign audience segments) for a client.

    Each cohort represents a targeting campaign combining an audience of specific
    people (targets), a buyer journey (warm-up → engagement → re-engagement stages),
    and ad creatives (content). Returns cohort IDs, names, and statuses.

    When a user asks: "What campaigns are running?", "Show me my cohorts",
    "What audience segments exist?", "List active campaigns",
    "Which ABM campaigns are live?", "How many campaigns does [client] have?"
    """
    try:
        cid = resolve_client_id(client_id)
        api_client = get_api_client()

        params: dict = {"limit": min(max(limit, 1), 100), "offset": max(offset, 0)}
        if status:
            params["status"] = status

        response = await api_client.get(f"/public/v1/clients/{cid}/cohorts", params=params)

        cohorts = response.get("data", response.get("items", []))
        paging = response.get("paging", {})

        # Strip target arrays from each cohort to stay under MCP's 1MB limit
        for cohort in cohorts:
            if isinstance(cohort, dict):
                targets = cohort.pop("targets", []) or []
                cohort["target_count"] = len(targets)

        result = {
            "cohorts": cohorts,
            "count": len(cohorts),
            "paging": paging,
            "_next_steps": [],
        }

        if cohorts:
            result["_next_steps"].append(
                "Get full details and metrics for a cohort with "
                "influ2_get_cohort_details(cohort_id='...')"
            )
        else:
            result["_next_steps"].append(
                "No cohorts found. Cohorts are created in the Influ2 UI."
            )

        return json.dumps(result, indent=2)

    except Influ2Error as e:
        return json.dumps(format_error_for_llm(e))
    except Exception as e:
        return json.dumps(format_error_for_llm(e))


@mcp.tool()
async def influ2_get_cohort_details(
    cohort_id: Annotated[str, "The cohort bundle ID to get details for"],
    client_id: Annotated[
        str | None,
        "Influ2 client ID. Omit to use configured default.",
    ] = None,
    include_metrics: Annotated[
        bool,
        "Include performance metrics (impressions, clicks, CTR, reached targets/buying groups)",
    ] = True,
    include_contents: Annotated[
        bool,
        "Include list of associated ad creatives/content",
    ] = True,
    metrics_from: Annotated[
        int | None,
        "Metrics start date as UNIX timestamp. Omit for all-time.",
    ] = None,
    metrics_to: Annotated[
        int | None,
        "Metrics end date as UNIX timestamp. Omit for up to now.",
    ] = None,
) -> str:
    """Get comprehensive details about a specific cohort bundle including configuration,
    performance metrics, and associated content/creatives — all in one call.

    This is the primary tool for answering "how is my campaign performing?" questions.
    Returns cohort info, journey config, impressions, clicks, CTR, reached targets,
    reached buying groups, and all ad creatives.

    When a user asks: "How is cohort X performing?", "Show me campaign metrics",
    "What's the CTR for my ABM campaign?", "How many targets have been reached?",
    "How many buying groups have we touched?", "Give me a full campaign report",
    "What ads are running and how are they doing?"
    """
    try:
        cid = resolve_client_id(client_id)
        api_client = get_api_client()

        # Fetch cohort details (always)
        cohort_data = await api_client.get(
            f"/public/v1/clients/{cid}/cohorts/{cohort_id}"
        )

        # Strip the targets array to avoid exceeding MCP's 1MB response limit.
        # Large cohorts can have thousands of targets that blow past the cap.
        _strip_targets_from_response(cohort_data)

        result = {"cohort": cohort_data}

        # Fetch metrics and contents in parallel
        tasks = []
        if include_metrics:
            metrics_params: dict = {}
            if metrics_from is not None:
                metrics_params["from"] = metrics_from
            if metrics_to is not None:
                metrics_params["to"] = metrics_to
            tasks.append(
                api_client.get(
                    f"/public/v1/clients/{cid}/cohorts/{cohort_id}/metrics",
                    params=metrics_params if metrics_params else None,
                )
            )
        if include_contents:
            tasks.append(
                api_client.get(
                    f"/public/v1/clients/{cid}/cohorts/{cohort_id}/contents"
                )
            )

        if tasks:
            responses = await asyncio.gather(*tasks, return_exceptions=True)
            idx = 0
            if include_metrics:
                metrics_resp = responses[idx]
                idx += 1
                if isinstance(metrics_resp, Exception):
                    result["metrics"] = {"_error": f"Could not fetch metrics: {metrics_resp}"}
                else:
                    result["metrics"] = metrics_resp
            if include_contents:
                contents_resp = responses[idx]
                if isinstance(contents_resp, Exception):
                    result["contents"] = {"_error": f"Could not fetch contents: {contents_resp}"}
                else:
                    result["contents"] = contents_resp

        result["_next_steps"] = [
            "Add or update targets with influ2_manage_targets(cohort_id='...')",
            "View content details with influ2_list_contents(scope='by_cohort', cohort_id='...')",
        ]

        return json.dumps(result, indent=2, default=str)

    except Influ2Error as e:
        return json.dumps(format_error_for_llm(e))
    except Exception as e:
        return json.dumps(format_error_for_llm(e))


