"""Tool: campaign_report — Detailed campaign analytics with outcomes and stale lead warnings.

Provides deeper analytics than show_status, focused on outcome tracking,
conversion rates, stale lead detection, and engagement ROI.
"""

from __future__ import annotations

import json
import logging
import time as _time

from ..db.queries import (
    find_active_campaign,
    get_campaign,
    get_campaign_outcomes,
    get_campaign_stats,
    get_campaign_velocity,
    get_cohort_analysis,
    get_engagement_stats,
    get_read_rate,
    get_setting,
    get_stale_outreaches,
    get_time_series_stats,
    get_variant_stats,
    list_ab_tests,
    list_campaigns,
)
from ..formatter import (
    conversion_rate_display,
    format_duration,
    funnel_bar,
    outcome_icon,
    outcome_label,
    progress_bar,
    sparkline,
    stars,
    table,
)

logger = logging.getLogger(__name__)


async def run_campaign_report(
    campaign_id: str = "",
) -> str:
    """Generate a detailed analytics report for a campaign.

    Args:
        campaign_id: Which campaign to report on. Uses the active campaign if empty.
    """

    # ── Pre-checks ──
    setup_done = get_setting("setup_complete", False)
    if not setup_done:
        return (
            "Setup required before generating reports.\n\n"
            "Please run setup_profile first."
        )

    # ── Resolve campaign ──
    campaign, err = find_active_campaign(campaign_id)
    if not campaign and not campaign_id:
        campaigns = list_campaigns()
        if not campaigns:
            return (
                "No campaigns to report on.\n\n"
                "Create one first: create_campaign(\"your target description\")"
            )
        campaign = campaigns[0]
    elif not campaign:
        return err

    campaign_id = campaign["id"]
    config = {}
    try:
        config = json.loads(campaign.get("config_json", "{}") or "{}")
    except (json.JSONDecodeError, TypeError):
        pass

    # ── Load all data ──
    stats = get_campaign_stats(campaign_id)
    outcomes = get_campaign_outcomes(campaign_id)
    eng_stats = get_engagement_stats(campaign_id)
    stale = get_stale_outreaches(campaign_id, stale_days=14)
    velocity = get_campaign_velocity(campaign_id)

    # Calculate days since creation
    created = campaign.get("created_at", 0)
    days = (int(_time.time()) - created) // 86400 if created else 0

    # ── Section 1: Header ──
    mode_str = "\U0001f916 Autopilot" if campaign.get("mode") == "autopilot" else "\U0001f464 Copilot"
    status_str = campaign.get("status", "active").capitalize()

    output = [
        f"\U0001f4ca Campaign Report: **{campaign['name']}** (Day {days})",
        f"   Mode: {mode_str} | Status: {status_str}",
        f"   Target: {config.get('target_description', 'N/A')}",
        "",
    ]

    # ── Section 2: Funnel ──
    total = stats.get("total_prospects", 0)
    invited = stats.get("invited", 0)
    connected = stats.get("connected", 0)
    replied = stats.get("replied", 0)
    hot = stats.get("hot_leads", 0)
    skipped = stats.get("skipped", 0)

    won = stats.get("closed_happy", 0)

    if total > 0:
        output.append("Funnel:")
        output.append(f"  {funnel_bar('Prospects', total, total)}")
        output.append(f"  {funnel_bar('Invited', invited, total)}")
        output.append(f"  {funnel_bar('Connected', connected, total)}")
        output.append(f"  {funnel_bar('Replied', replied, total)}")
        output.append(f"  {funnel_bar('Hot Lead', hot, total)}")
        output.append(f"  {funnel_bar('Won', won, total)}")
        output.append("")

    # ── Section 2.5: Velocity (time-based metrics) ──
    avg_tta = velocity.get("avg_time_to_accept")
    avg_ttr = velocity.get("avg_time_to_reply")
    avg_full = velocity.get("avg_time_invite_to_reply")
    cnt_accept = velocity.get("count_accepted", 0)
    cnt_reply = velocity.get("count_replied", 0)

    if cnt_accept > 0 or cnt_reply > 0:
        output.append("Velocity:")
        if cnt_accept > 0:
            output.append(f"\u251c\u2500\u2500 Avg time to accept: {format_duration(avg_tta)} (n={cnt_accept})")
            fastest = velocity.get("fastest_accept")
            slowest = velocity.get("slowest_accept")
            if fastest is not None and slowest is not None and cnt_accept > 1:
                output.append(f"\u2502   Range: {format_duration(fastest)} \u2014 {format_duration(slowest)}")
        if cnt_reply > 0:
            output.append(f"\u251c\u2500\u2500 Avg time to reply: {format_duration(avg_ttr)} (n={cnt_reply})")
        if avg_full is not None:
            output.append(f"\u2514\u2500\u2500 Avg invite \u2192 reply: {format_duration(avg_full)}")
        output.append("")

    # ── Section 2.6: Read rate ──
    read_data = get_read_rate(campaign_id)
    if read_data["total_sdr_messages"] > 0:
        rr = read_data["read_rate"]
        read_count = read_data["read_messages"]
        total_msgs = read_data["total_sdr_messages"]
        output.append(f"Read rate: {rr:.0%} ({read_count}/{total_msgs} messages read)")
        output.append("")

    # ── Section 3: Outcomes ──
    closed_happy = outcomes.get("closed_happy", 0)
    closed_unhappy = outcomes.get("closed_unhappy", 0)
    opted_out = outcomes.get("opted_out", 0)
    total_closed = outcomes.get("total_closed", 0)

    # Count active leads
    active_hot = hot
    active_replied = stats.get("replied", 0) - closed_happy - closed_unhappy
    if active_replied < 0:
        active_replied = 0

    output.append("Outcomes:")
    output.append(f"\u251c\u2500\u2500 \U0001f3c6 Won: {closed_happy}")
    output.append(f"\u251c\u2500\u2500 \U0001f4c9 Lost: {closed_unhappy}")
    if opted_out > 0:
        output.append(f"\u251c\u2500\u2500 \U0001f6ab Opted out: {opted_out}")
    output.append(f"\u251c\u2500\u2500 Conversion: {conversion_rate_display(closed_happy, closed_unhappy)}")

    active_parts = []
    if active_hot > 0:
        active_parts.append(f"{active_hot} hot")
    if active_replied > 0:
        active_parts.append(f"{active_replied} replied")
    active_str = ", ".join(active_parts) if active_parts else "none"
    output.append(f"\u2514\u2500\u2500 Active leads: {active_str}")
    output.append("")

    # ── Section 4: Won deals detail ──
    won_deals = [o for o in outcomes.get("outcomes", []) if o["status"] == "closed_happy"]
    deal_timelines = {t["name"]: t for t in velocity.get("per_deal_timelines", [])}
    if won_deals:
        output.append("Won deals:")
        for i, deal in enumerate(won_deals):
            is_last = i == len(won_deals) - 1
            prefix = "\u2514\u2500\u2500" if is_last else "\u251c\u2500\u2500"
            role = deal.get("title", "")
            if deal.get("company"):
                role += f" at {deal['company']}" if role else deal["company"]
            reason_str = f" ({deal['reason']})" if deal.get("reason") else ""
            output.append(f"{prefix} {deal['name']} \u2014 {role}{reason_str}")
            # Per-deal timeline
            tl = deal_timelines.get(deal["name"])
            if tl:
                parts = []
                if tl.get("time_to_accept") is not None:
                    parts.append(f"accept: {format_duration(tl['time_to_accept'])}")
                if tl.get("time_to_reply") is not None:
                    parts.append(f"reply: {format_duration(tl['time_to_reply'])}")
                if parts:
                    cont = "    " if is_last else "\u2502   "
                    output.append(f"{cont}Timeline: {' \u2192 '.join(parts)}")
        output.append("")

    # ── Section 5: Lost deals detail (if any) ──
    lost_deals = [o for o in outcomes.get("outcomes", []) if o["status"] == "closed_unhappy"]
    if lost_deals:
        output.append("Lost deals:")
        for i, deal in enumerate(lost_deals):
            is_last = i == len(lost_deals) - 1
            prefix = "\u2514\u2500\u2500" if is_last else "\u251c\u2500\u2500"
            role = deal.get("title", "")
            if deal.get("company"):
                role += f" at {deal['company']}" if role else deal["company"]
            reason_str = f" ({deal['reason']})" if deal.get("reason") else ""
            output.append(f"{prefix} {deal['name']} \u2014 {role}{reason_str}")
        output.append("")

    # ── Section 6: Stale leads warning ──
    if stale:
        output.append(f"\u26a0\ufe0f Stale leads (no activity 14+ days):")
        for i, s in enumerate(stale[:5]):
            is_last = i == min(4, len(stale) - 1)
            prefix = "\u2514\u2500\u2500" if is_last else "\u251c\u2500\u2500"
            role = s.get("title", "")
            if s.get("company"):
                role += f" at {s['company']}" if role else s["company"]
            output.append(f"{prefix} {s['name']} \u2014 {role} (last activity: {s['days_stale']}d ago)")
        if len(stale) > 5:
            output.append(f"    ... and {len(stale) - 5} more")
        output.append(f"   \u2192 Use close_outreach() to resolve or send_followup() to re-engage")
        output.append("")

    # ── Section 7: Engagement metrics ──
    comments = eng_stats.get("comments", 0)
    reactions = eng_stats.get("reactions", 0)
    eng_total = comments + reactions
    if eng_total > 0:
        output.append("Engagement:")
        output.append(f"\u251c\u2500\u2500 Comments: {comments}")
        output.append(f"\u251c\u2500\u2500 Reactions: {reactions}")
        output.append(f"\u2514\u2500\u2500 Total touches: {eng_total}")
        output.append("")

    # ── Section 8: Account health ──
    acc_rate = stats.get("acceptance_rate", 0)
    if invited > 0:
        mature = stats.get("mature_acceptance_rate", 0)
        output.append(f"Acceptance rate: {acc_rate:.0%}")
        if mature > 0 and mature != acc_rate:
            output.append(f"   (7-day mature rate: {mature:.0%})")
        output.append("")

    # ── Section 9: A/B Test Results ──
    v_stats = get_variant_stats(campaign_id)
    if "A" in v_stats and "B" in v_stats:
        va = v_stats["A"]
        vb = v_stats["B"]
        output.append("A/B Test Split:")
        output.append(
            f"\u251c\u2500\u2500 Variant A: {va['total']} prospects, "
            f"{va['acceptance_rate']}% accept, {va['reply_rate']}% reply, "
            f"{va.get('won', 0)} won"
        )
        output.append(
            f"\u2514\u2500\u2500 Variant B: {vb['total']} prospects, "
            f"{vb['acceptance_rate']}% accept, {vb['reply_rate']}% reply, "
            f"{vb.get('won', 0)} won"
        )
        # Show running tests
        running = list_ab_tests(campaign_id, status="running")
        for t in running:
            output.append(f"   Running: {t['name']}")
            output.append(f"     A: {t['variant_a']}")
            output.append(f"     B: {t['variant_b']}")
        # Show completed tests
        completed = list_ab_tests(campaign_id, status="completed")
        for t in completed[:2]:
            winner = t.get("winner", "?")
            output.append(f"   Completed: {t['name']} \u2192 Winner: Variant {winner}")
        output.append("")

    # ── Section 9.5: Experiment Insights + A/B Evaluation ──
    try:
        from ..services.experiment_service import evaluate_ab_tests, get_experiment_summary
        ab_results = evaluate_ab_tests()
        for r in ab_results:
            output.append(f"  {r}")
        exp_insight = get_experiment_summary(campaign_id)
        if exp_insight:
            output.append("Experiment Insights:")
            output.append(f"  {exp_insight}")
            output.append("")
    except Exception:
        pass

    # ── Section 10: Cohort Analysis ──
    cohorts = get_cohort_analysis(campaign_id)
    real_cohorts = [c for c in cohorts if c["cohort"] != "Not invited"]
    if len(real_cohorts) >= 2:
        output.append("📊 Cohort Analysis (by invitation week):")
        cohort_headers = ["Week", "Invited", "Connected", "Replied", "Accept%", "Reply%"]
        cohort_rows = []
        for c in real_cohorts:
            cohort_rows.append([
                c["cohort"],
                str(c.get("invited", 0)),
                str(c.get("connected", 0)),
                str(c.get("replied", 0)),
                f"{c['acceptance_rate']:.0f}%",
                f"{c['reply_rate']:.0f}%",
            ])
        output.append(table(cohort_headers, cohort_rows))
        output.append("")

    # ── Section 11: Activity Timeline ──
    ts_data = get_time_series_stats(campaign_id)
    if len(ts_data) >= 3:
        invite_vals = [d.get("invites", 0) for d in ts_data]
        reply_vals = [d.get("replies", 0) for d in ts_data]
        output.append("📈 Activity (last 30 days):")
        output.append(f"  Invites:     {sparkline(invite_vals)} (total: {sum(invite_vals)})")
        output.append(f"  Replies:     {sparkline(reply_vals)} (total: {sum(reply_vals)})")
        if ts_data:
            output.append(f"  Period: {ts_data[0]['date']} → {ts_data[-1]['date']}")
        output.append("")

    # ── Section 12: Remaining queue ──
    pending = total - invited - skipped
    if pending > 0:
        output.append(f"\U0001f4e6 {pending} prospects still queued for outreach.")

    return "\n".join(output)
