"""Tools 26-27: scheduler_status + toggle_scheduler.

Provides visibility into and control over the autonomous scheduler.
Supports both local (in-process) and cloud (backend) scheduling modes.
"""

from __future__ import annotations

import logging
import time
from datetime import datetime
from typing import Any

from ..config import is_scheduler_enabled, set_scheduler_enabled, is_backend_mode
from ..db.queries import (
    get_scheduler_stats,
    get_recent_scheduler_events,
    get_scheduler_event_summary,
    get_job_metrics,
    get_rate_limit_today,
    list_campaigns,
    get_setting,
    count_outreaches_by_status,
)

logger = logging.getLogger(__name__)


async def run_scheduler_status() -> str:
    """Show scheduler status, pending jobs, and recent activity.

    If in backend mode, also shows cloud scheduler status.
    """
    from ..config import is_scheduler_always_on

    enabled = is_scheduler_enabled()
    always_on = is_scheduler_always_on()
    stats = get_scheduler_stats()
    now = int(time.time())

    # ── Header ──
    status_icon = "\u2601\ufe0f" if enabled else "\u23f8\ufe0f"
    lines = [
        f"# {status_icon} Scheduler {'Enabled' if enabled else 'Disabled'}",
        "",
    ]

    if always_on:
        lines.append("**Always-On**: Active (auto-re-enables if disabled, sends immediate alerts)")
        lines.append("")

    if not enabled:
        lines.append(
            "The autonomous scheduler is currently **off**.\n"
            "Enable it with: `scheduler(action='toggle', enabled=True)`\n\n"
            "When enabled, the scheduler will automatically:\n"
            "- Send invitations to pending prospects (autopilot campaigns)\n"
            "- Send follow-ups on schedule (1, 7, 14, 21, 28 days)\n"
            "- Check for replies every 5 minutes\n"
            "- Engage with prospect posts every 30 minutes\n"
            "- Respect rate limits, working hours, and daily caps"
        )
        # Still show cloud status if available
        cloud_section = await _cloud_status_section()
        if cloud_section:
            lines.append("")
            lines.append(cloud_section)
        return "\n".join(lines)

    # ── Job Counts ──
    counts = stats.get("counts", [])
    if counts:
        lines.append("## Job Queue")
        lines.append("")
        lines.append("| Status | Type | Count |")
        lines.append("|--------|------|-------|")
        for row in counts:
            status = row["status"]
            job_type = row["job_type"]
            cnt = row["cnt"]
            icon = {"pending": "\u23f3", "running": "\U0001f504", "completed": "\u2705", "failed": "\u274c"}.get(status, "")
            lines.append(f"| {icon} {status} | {job_type} | {cnt} |")
        lines.append("")
    else:
        lines.append("\U0001f4ed No jobs in queue\n")

    # ── Next Scheduled ──
    next_jobs = stats.get("next_jobs", [])
    if next_jobs:
        lines.append("## Next Scheduled")
        lines.append("")
        for job in next_jobs:
            scheduled = job["scheduled_at"]
            delta = scheduled - now
            if delta > 0:
                mins = delta // 60
                when = f"in {mins} min" if mins > 0 else "now"
            else:
                when = "overdue"

            job_type = job["job_type"]
            outreach = job.get("outreach_id", "")
            target = f" (outreach: {outreach[:8]}...)" if outreach else ""
            lines.append(f"- **{job_type}** {when}{target}")
        lines.append("")

    # ── Recent Activity ──
    recent = stats.get("recent", [])
    if recent:
        lines.append("## Recent Activity")
        lines.append("")
        for job in recent[:5]:
            completed = job.get("completed_at", 0)
            ago = (now - completed) // 60 if completed else 0
            status = job["status"]
            icon = "\u2705" if status == "completed" else "\u274c"
            error = job.get("error", "")
            error_text = f" \u2014 {error[:50]}" if error else ""
            lines.append(
                f"- {icon} **{job['job_type']}** {ago} min ago{error_text}"
            )
        lines.append("")

    # ── 24h Metrics Summary ──
    metrics = get_job_metrics(24)
    if metrics:
        total_jobs = sum(m["total"] for m in metrics.values())
        total_ok = sum(m["success"] for m in metrics.values())
        total_fail = sum(m["failed"] for m in metrics.values())
        overall_rate = round(total_ok / total_jobs * 100, 1) if total_jobs > 0 else 0
        lines.append("## 24h Metrics")
        lines.append("")
        lines.append(
            f"Jobs: **{total_jobs}** | Success: **{total_ok}** | "
            f"Failed: **{total_fail}** | Rate: **{overall_rate}%**"
        )
        if total_fail > 0:
            lines.append(
                f"\nUse `scheduler(action='logs')` to see failure details."
            )
        lines.append("")

    # ── Brand Automation ──
    brand_section = _brand_automation_section(stats)
    if brand_section:
        lines.append(brand_section)
        lines.append("")

    # ── Cloud Status ──
    cloud_section = await _cloud_status_section()
    if cloud_section:
        lines.append(cloud_section)

    # ── Quick Actions ──
    lines.append("## Quick Actions")
    lines.append("- `scheduler(action='toggle', enabled=False)` \u2014 pause the scheduler")
    lines.append("- `scheduler(action='toggle', enabled=True, cloud=True)` \u2014 enable cloud 24/7 scheduling")
    lines.append("- `scheduler(action='logs')` \u2014 detailed event log and job metrics")
    lines.append("- `scheduler(action='diagnostics')` \u2014 full system diagnostics")
    lines.append("- `show_status()` \u2014 view campaign dashboard")
    lines.append("- `campaign(action='emergency_stop')` \u2014 pause all campaigns immediately")

    return "\n".join(lines)


def _brand_automation_section(stats: dict[str, Any]) -> str:
    """Build brand automation status section if brand plan exists."""
    from ..db.queries import get_setting
    from ..formatter import progress_bar

    brand_plan = get_setting("brand_strategy")
    if not brand_plan or not isinstance(brand_plan, dict) or not brand_plan.get("weeks"):
        return ""

    total = sum(len(w.get("actions", [])) for w in brand_plan.get("weeks", []))
    done = sum(
        1 for w in brand_plan.get("weeks", [])
        for a in w.get("actions", []) if a.get("status") == "completed"
    )

    lines = [
        "## \U0001f3af Brand Automation",
        "",
        f"**Progress**: {done}/{total} actions {progress_bar(done, total, 15)}",
    ]

    # Show next scheduled brand jobs from stats
    next_jobs = stats.get("next_jobs", [])
    brand_jobs = [j for j in next_jobs if j.get("job_type", "").startswith("brand_")]
    if brand_jobs:
        now = int(time.time())
        for job in brand_jobs[:3]:
            delta = job["scheduled_at"] - now
            if delta > 0:
                mins = delta // 60
                when = f"in {mins} min" if mins > 0 else "now"
            else:
                when = "overdue"
            lines.append(f"- Next **{job['job_type']}** {when}")
    else:
        if done < total:
            lines.append("- Posts + engagements run automatically via scheduler")
        else:
            lines.append("- All actions complete! Re-analysis scheduled at 28-day mark")

    # Show automation status
    lines.append("")
    lines.append("Automation runs: posts (~2-3/week), engagements (~5/day), re-analyze (every 28d)")

    return "\n".join(lines)


async def _cloud_status_section() -> str:
    """Build cloud scheduler status section if in backend mode."""
    if not is_backend_mode():
        return ""

    try:
        from ..services.cloud_sync import get_cloud_scheduler_status

        cloud = await get_cloud_scheduler_status()
        if "error" in cloud:
            return f"## \u2601\ufe0f Cloud Scheduler\n\n\u26a0\ufe0f {cloud['error']}"

        cloud_enabled = cloud.get("enabled", False)
        pending = cloud.get("pending_jobs", 0)
        campaigns = cloud.get("campaigns", [])

        icon = "\U0001f7e2" if cloud_enabled else "\u23f8\ufe0f"
        lines = [
            f"## \u2601\ufe0f Cloud Scheduler {icon} {'Enabled' if cloud_enabled else 'Disabled'}",
            "",
        ]

        if cloud_enabled:
            lines.append(f"**Pending jobs**: {pending}")
            if campaigns:
                lines.append(f"**Cloud campaigns**: {len(campaigns)}")
                for c in campaigns[:5]:
                    lines.append(f"  - {c.get('name', 'Unknown')} ({c.get('status', '?')})")
            lines.append("")
            lines.append("The backend processes outreach every 5 min, 24/7.")

            # Recent cloud activity
            recent = cloud.get("recent_activity", [])
            if recent:
                lines.append("")
                lines.append("**Recent cloud activity:**")
                for job in recent[:3]:
                    jtype = job.get("job_type", "?")
                    status = job.get("status", "?")
                    icon = "\u2705" if status == "completed" else "\u274c"
                    lines.append(f"  {icon} {jtype} ({status})")
        else:
            lines.append(
                "Cloud scheduling is off. Enable with:\n"
                "`toggle_scheduler(enabled=True, cloud=True)`"
            )

        return "\n".join(lines)
    except Exception as e:
        logger.debug("Cloud status check failed: %s", e)
        return ""


async def run_toggle_scheduler(enabled: bool, cloud: bool = False) -> str:
    """Enable or disable the autonomous scheduler.

    Args:
        enabled: Whether to enable (True) or disable (False).
        cloud: If True, toggle the cloud (backend) scheduler for 24/7 operation.
               If False, toggle the local (in-process) scheduler.
    """
    if cloud:
        from ..services.cloud_sync import toggle_cloud_scheduler
        return await toggle_cloud_scheduler(enabled)

    # Local scheduler toggle (unchanged)
    was_enabled = is_scheduler_enabled()

    if enabled == was_enabled:
        state = "enabled" if enabled else "disabled"
        return f"Scheduler is already {state}. No change made."

    action_label = "enabled" if enabled else "disabled"
    set_scheduler_enabled(
        enabled,
        caller="mcp_tool",
        reason=f"User {action_label} via scheduler(action='toggle')",
    )

    if enabled:
        return (
            "\U0001f7e2 **Scheduler enabled!**\n\n"
            "The scheduler will now automatically process outreach for **autopilot** campaigns:\n"
            "- Send invitations (20-40 min randomized delays)\n"
            "- Send follow-ups (on schedule: day 1, 7, 14, 21, 28)\n"
            "- Check for replies (every 5 min)\n"
            "- Engage with prospect posts (every 30 min)\n\n"
            "All actions respect working hours, rate limits, and daily caps.\n"
            "Copilot campaigns still require manual approval.\n\n"
            "Use `scheduler(action='status')` to monitor progress.\n\n"
            "\U0001f4a1 **Tip**: For 24/7 scheduling (even when laptop is off), use:\n"
            "`scheduler(action='toggle', enabled=True, cloud=True)`"
        )
    else:
        return (
            "\u23f8\ufe0f **Scheduler disabled.**\n\n"
            "Autonomous outreach has been paused. No new jobs will be scheduled.\n"
            "Already-running jobs will complete, but no new ones will start.\n\n"
            "Your campaigns are still active \u2014 you can manually send with:\n"
            "- `generate_and_send()` \u2014 send an invitation\n"
            "- `send_message(action='followup')` \u2014 send a follow-up\n"
            "- `check_replies()` \u2014 check for replies\n\n"
            "Use `scheduler(action='toggle', enabled=True)` to re-enable."
        )


async def run_toggle_always_on(enabled: bool) -> str:
    """Enable or disable scheduler always-on mode.

    When enabled, the scheduler automatically re-enables itself if anything
    turns it off, and sends an immediate email alert with attribution.
    """
    from ..config import (
        is_scheduler_always_on,
        is_scheduler_enabled,
        set_scheduler_always_on,
        set_scheduler_enabled,
    )

    was_on = is_scheduler_always_on()
    if enabled == was_on:
        state = "enabled" if enabled else "disabled"
        return f"Scheduler always-on mode is already {state}. No change made."

    set_scheduler_always_on(enabled)

    if enabled:
        # Also ensure scheduler is enabled when turning on always-on
        if not is_scheduler_enabled():
            set_scheduler_enabled(
                True,
                caller="always_on_activation",
                reason="Auto-enabled when always-on mode was activated",
            )

        # Sync always_on to cloud if in backend mode
        await _sync_always_on_to_cloud(True)

        return (
            "**Scheduler always-on mode ENABLED.**\n\n"
            "The scheduler will now:\n"
            "- Automatically re-enable itself if anything turns it off\n"
            "- Send an immediate email alert when a disable event is detected\n"
            "- Include full attribution (who/what/why) in the alert\n\n"
            "This ensures your campaigns never silently stop running.\n\n"
            "To disable: `scheduler(action='always_on', enabled=False)`"
        )
    else:
        # Sync always_on to cloud
        await _sync_always_on_to_cloud(False)

        return (
            "**Scheduler always-on mode DISABLED.**\n\n"
            "The scheduler can now be freely toggled on/off without auto-re-enable.\n"
            "No alerts will be sent when the scheduler is disabled."
        )


async def _sync_always_on_to_cloud(enabled: bool) -> None:
    """Sync the always_on preference to the backend (if in backend mode)."""
    from ..config import is_backend_mode

    if not is_backend_mode():
        return

    try:
        import httpx
        from ..services.cloud_sync import _base_url, _headers

        base = _base_url()
        async with httpx.AsyncClient(timeout=15.0) as client:
            await client.post(
                f"{base}/api/v1/scheduler/always-on",
                json={"always_on": enabled},
                headers=_headers(),
            )
    except Exception as e:
        logger.debug("Failed to sync always_on to cloud: %s", e)


async def run_scheduler_logs(
    hours: int = 24,
    event_type: str = "",
    campaign_id: str = "",
) -> str:
    """Show scheduler event log with metrics and recent failures.

    Args:
        hours: Lookback window in hours (default 24).
        event_type: Filter by event type (e.g. 'job_failed').
        campaign_id: Filter by campaign ID.
    """
    summary = get_scheduler_event_summary(hours)
    metrics = get_job_metrics(hours)
    failures = get_recent_scheduler_events(
        hours=hours, event_type="job_failed",
        campaign_id=campaign_id, limit=10,
    )

    lines = [f"# Scheduler Events ({hours}h)", ""]

    # ── Event Summary ──
    if summary:
        parts = [f"{etype}: **{cnt}**" for etype, cnt in summary.items()]
        lines.append(" | ".join(parts))
        lines.append("")
    else:
        lines.append("No events recorded in this window.")
        lines.append("")
        return "\n".join(lines)

    # ── Job Metrics Table ──
    if metrics:
        lines.append("## Job Metrics")
        lines.append("")
        lines.append("| Type | Total | OK | Fail | Rate | Avg Duration |")
        lines.append("|------|-------|----|------|------|-------------|")
        for jtype, m in sorted(metrics.items(), key=lambda x: x[1]["total"], reverse=True):
            avg_dur = m["avg_duration_ms"]
            dur_str = f"{avg_dur / 1000:.1f}s" if avg_dur else "—"
            lines.append(
                f"| {jtype} | {m['total']} | {m['success']} | {m['failed']} "
                f"| {m['success_rate']}% | {dur_str} |"
            )
        lines.append("")

    # ── Recent Failures ──
    if failures:
        lines.append("## Recent Failures")
        lines.append("")
        for evt in failures[:10]:
            ts = evt.get("created_at", 0)
            t = datetime.fromtimestamp(ts).strftime("%H:%M") if ts else "?"
            ctx = evt.get("context", {})
            jtype = ctx.get("job_type", "?")
            cat = ctx.get("error_category", "")
            err = ctx.get("error", "")[:80]
            cat_tag = f" [{cat}]" if cat else ""
            job_id = (evt.get("job_id") or "")[:8]
            lines.append(f"- [{t}] {jtype} {job_id}{cat_tag}: {err}")
        lines.append("")

    # ── Quick Actions ──
    lines.append("## Quick Actions")
    lines.append("- `scheduler(action='logs', hours=48)` — wider window")
    lines.append("- `scheduler(action='diagnostics')` — full system diagnostics")
    lines.append("- `campaign(action='retry_failed')` — retry failed outreaches")

    return "\n".join(lines)


async def run_scheduler_diagnostics(campaign_id: str = "") -> str:
    """Full diagnostics: rate limits, campaign breakdown, timer health, blockers.

    Args:
        campaign_id: Focus on a specific campaign. Shows all if empty.
    """
    now = int(time.time())
    lines = ["# Scheduler Diagnostics", ""]

    # ── Rate Limits ──
    rl = get_rate_limit_today()
    daily_limit = rl.get("daily_limit", 15)
    sent = rl.get("sent", 0)
    remaining = max(0, daily_limit - sent)
    blocked = rl.get("blocked", False)
    blocked_str = " **BLOCKED**" if blocked else ""
    lines.append("## Rate Limits")
    lines.append("")
    lines.append(f"- Sent today: **{sent}/{daily_limit}** ({remaining} remaining){blocked_str}")
    lines.append("")

    # ── Active Campaigns ──
    campaigns = list_campaigns(status="active")
    if campaign_id:
        campaigns = [c for c in campaigns if c["id"] == campaign_id]

    if campaigns:
        lines.append("## Campaign Breakdown")
        lines.append("")
        lines.append("| Campaign | Mode | Pending | Connected | Followup | Finished |")
        lines.append("|----------|------|---------|-----------|----------|----------|")
        for c in campaigns:
            cid = c["id"]
            name = (c.get("name") or "Unnamed")[:25]
            mode = c.get("mode", "?")
            pending = count_outreaches_by_status(cid, "pending")
            connected = count_outreaches_by_status(cid, "connected")
            followup = count_outreaches_by_status(cid, "followup_due")
            finished = count_outreaches_by_status(cid, "finished")
            lines.append(
                f"| {name} | {mode} | {pending} | {connected} | {followup} | {finished} |"
            )
        lines.append("")
    else:
        lines.append("## Campaigns")
        lines.append("")
        lines.append("No active campaigns found.")
        lines.append("")

    # ── Scheduler State ──
    enabled = is_scheduler_enabled()
    lines.append("## Scheduler State")
    lines.append("")
    from ..config import is_scheduler_always_on as _is_always_on
    lines.append(f"- Scheduler: **{'enabled' if enabled else 'disabled'}**")
    lines.append(f"- Always-on: **{'active' if _is_always_on() else 'inactive'}**")
    lines.append(f"- Mode: **{'backend' if is_backend_mode() else 'local'}**")

    # Timer health from persisted state
    timers_raw = get_setting("scheduler_timers")
    if timers_raw and isinstance(timers_raw, dict):
        lines.append("")
        lines.append("## Timer Health")
        lines.append("")
        lines.append("| Timer | Last Fired | Age |")
        lines.append("|-------|-----------|-----|")
        for name, ts in sorted(timers_raw.items(), key=lambda x: x[1], reverse=True):
            if not ts:
                lines.append(f"| {name} | never | — |")
                continue
            fired = datetime.fromtimestamp(ts).strftime("%H:%M:%S")
            age_s = now - int(ts)
            if age_s < 60:
                age_str = f"{age_s}s"
            elif age_s < 3600:
                age_str = f"{age_s // 60}m"
            else:
                age_str = f"{age_s // 3600}h {(age_s % 3600) // 60}m"
            lines.append(f"| {name} | {fired} | {age_str} ago |")
        lines.append("")

    # ── Job Queue Health ──
    stats = get_scheduler_stats()
    counts = stats.get("counts", [])
    running = sum(r["cnt"] for r in counts if r["status"] == "running")
    pending = sum(r["cnt"] for r in counts if r["status"] == "pending")
    failed = sum(r["cnt"] for r in counts if r["status"] == "failed")

    lines.append("## Job Queue Health")
    lines.append("")
    lines.append(f"- Running: **{running}** | Pending: **{pending}** | Failed: **{failed}**")

    if failed > 0:
        lines.append(f"- Use `campaign(action='retry_failed')` to retry {failed} failed jobs")

    # ── Event Log Metrics (24h) ──
    metrics = get_job_metrics(24)
    if metrics:
        total_jobs = sum(m["total"] for m in metrics.values())
        total_ok = sum(m["success"] for m in metrics.values())
        total_fail = sum(m["failed"] for m in metrics.values())
        overall_rate = round(total_ok / total_jobs * 100, 1) if total_jobs > 0 else 0
        lines.append("")
        lines.append("## 24h Summary")
        lines.append("")
        lines.append(
            f"- Jobs executed: **{total_jobs}** "
            f"(success: {total_ok}, failed: {total_fail}, rate: {overall_rate}%)"
        )

        # Flag slow executors
        slow = [(jt, m) for jt, m in metrics.items() if m["avg_duration_ms"] > 5000]
        if slow:
            lines.append("- Slow executors (>5s avg):")
            for jtype, m in slow:
                lines.append(f"  - {jtype}: {m['avg_duration_ms'] / 1000:.1f}s avg")

    lines.append("")

    # ── Potential Issues ──
    issues = []
    if blocked:
        issues.append("Rate limit is BLOCKED — no invitations will be sent")
    if remaining == 0:
        issues.append("Daily send limit reached — invitations resume tomorrow")
    if running > 10:
        issues.append(f"{running} jobs running simultaneously — possible stuck jobs")
    if failed > 5:
        issues.append(f"{failed} failed jobs in queue — retry or investigate")
    if not enabled:
        issues.append("Scheduler is disabled — enable with scheduler(action='toggle', enabled=True)")

    if issues:
        lines.append("## Potential Issues")
        lines.append("")
        for issue in issues:
            lines.append(f"- {issue}")
    else:
        lines.append("## Status: All Clear")
        lines.append("No issues detected.")

    return "\n".join(lines)
