"""
Example plugin: real-time network monitor.

Copy this folder to ~/.mugi/plugins/realtime_network_monitor and approve it in
Settings > Plugins. It demonstrates the stream lifecycle API:
open_stream -> push_stream_update -> close_stream / emit_stream_error.
"""

from __future__ import annotations

import re
import threading
import time
from langchain_core.tools import tool

from tools.web_tools import capture_network_traffic


def _estimate_packets(output: str) -> float:
    text = output or ""
    m = re.search(r"\(~\s*(\d+)\s*packets\)", text, re.IGNORECASE)
    if m:
        try:
            return float(int(m.group(1)))
        except ValueError:
            pass
    # Fallback: rough line-based estimate.
    lines = [ln for ln in text.splitlines() if ln.strip()]
    return float(max(0, len(lines) // 2))


def _extract_issue_count(output: str) -> float:
    text = (output or "").lower()
    return float(text.count("retransmit") + text.count("unreachable") + text.count("ttl exceeded"))


def _default_controls() -> list[dict]:
    return [
        {
            "id": "top_pid_count",
            "type": "slider",
            "label": "Top PIDs",
            "min": 1,
            "max": 8,
            "step": 1,
            "default": 3,
        },
        {
            "id": "capture_type",
            "type": "select",
            "label": "Capture Type",
            "options": ["general", "http", "dns", "icmp", "tcp-syn"],
            "default": "general",
        },
        {
            "id": "realtime_mode",
            "type": "toggle",
            "label": "Realtime mode",
            "default": True,
        },
        {
            "id": "stop_now",
            "type": "button",
            "label": "Stop (next run)",
            "action_id": "stop_capture",
            "style": "destructive",
        },
    ]


def _make_tools(ctx, state: dict, state_lock: threading.Lock):
    @tool
    def monitor_network_live(
        packet_count: int = 120,
        capture_type: str = "general",
        duration_seconds: int = 15,
    ) -> str:
        """Capture network traffic and stream live metrics to the plugin dashboard."""
        stream_id = ctx.open_stream(
            stream_type="timeseries",
            title="Realtime Network Monitor",
            metadata={
                "unit": "packets",
                "capture_type": capture_type,
            },
        )
        ctx.register_stream_controls(stream_id, _default_controls())
        start_ms = int(time.time() * 1000)
        try:
            with state_lock:
                run_capture_type = str(state.get("capture_type") or capture_type)
                run_top_pid_count = int(state.get("top_pid_count") or 3)
                run_realtime = bool(state.get("realtime_mode", True))
                run_stop_requested = bool(state.get("stop_requested", False))
                state["active_stream_id"] = stream_id
            ctx.push_stream_update(
                stream_id,
                {
                    "status": "running",
                    "message": (
                        f"Starting capture (type={run_capture_type}, top_pid_count={run_top_pid_count}, "
                        f"realtime={run_realtime}, stop_requested={run_stop_requested})..."
                    ),
                    "metrics": {"progress_pct": 5, "top_pid_count": float(run_top_pid_count)},
                },
            )

            result = capture_network_traffic.invoke(
                {
                    "packet_count": 0 if run_realtime else packet_count,
                    "capture_type": run_capture_type,
                    "duration_seconds": duration_seconds,
                    "realtime": run_realtime,
                    "top_pid_count": run_top_pid_count,
                }
            )
            output = str(result)
            packets = _estimate_packets(output)
            issues = _extract_issue_count(output)
            elapsed_s = max(0.1, (int(time.time() * 1000) - start_ms) / 1000.0)
            packets_per_second = packets / elapsed_s

            ctx.push_stream_update(
                stream_id,
                {
                    "status": "captured",
                    "message": "Capture completed.",
                    "metrics": {
                        "packets_total": packets,
                        "packets_per_second": packets_per_second,
                        "issue_mentions": issues,
                        "progress_pct": 100,
                    },
                },
            )
            ctx.close_stream(
                stream_id,
                status="completed",
                payload={"message": "Monitor run finished."},
            )
            return output
        except Exception as e:
            msg = f"monitor_network_live failed: {e}"
            ctx.emit_stream_error(stream_id, msg)
            ctx.close_stream(stream_id, status="error", payload={"message": msg})
            return msg
        finally:
            with state_lock:
                if state.get("active_stream_id") == stream_id:
                    state["active_stream_id"] = None

    return [monitor_network_live]


def register(ctx):
    ctx.log("Realtime Network Monitor plugin loading...")
    state_lock = threading.Lock()
    control_state = {
        "top_pid_count": 3,
        "capture_type": "general",
        "realtime_mode": True,
        "stop_requested": False,
        "active_stream_id": None,
    }

    def _on_control(event, plugin_ctx):
        stream_id = str(event.get("stream_id") or "")
        control_id = str(event.get("control_id") or "")
        value = event.get("value")
        action_id = str(event.get("action_id") or "")
        with state_lock:
            if control_id == "top_pid_count":
                try:
                    control_state["top_pid_count"] = max(1, min(8, int(float(value))))
                except Exception:
                    return {"status": "rejected", "message": "top_pid_count must be numeric."}
            elif control_id == "capture_type":
                choice = str(value or "general")
                if choice not in {"general", "http", "dns", "icmp", "tcp-syn"}:
                    return {"status": "rejected", "message": f"Invalid capture_type '{choice}'."}
                control_state["capture_type"] = choice
            elif control_id == "realtime_mode":
                control_state["realtime_mode"] = bool(value)
            elif control_id == "stop_now" and action_id == "stop_capture":
                control_state["stop_requested"] = True
            else:
                return {"status": "rejected", "message": f"Unknown control '{control_id}'."}
            active_sid = control_state.get("active_stream_id")
            snapshot = dict(control_state)
        target_sid = active_sid or stream_id
        plugin_ctx.push_stream_update(
            target_sid,
            {
                "status": "running",
                "message": (
                    f"Control updated: {control_id}={value} "
                    f"(capture_type={snapshot['capture_type']}, top_pid_count={snapshot['top_pid_count']}, "
                    f"realtime={snapshot['realtime_mode']})"
                ),
                "metrics": {"top_pid_count": float(snapshot["top_pid_count"])},
            },
        )
        return {"status": "applied", "message": f"{control_id} updated."}

    ctx.register_control_handler(_on_control)
    ctx.register_tools(_make_tools(ctx, control_state, state_lock))
    ctx.log("Realtime Network Monitor plugin loaded.")
