from __future__ import annotations

import sys
import time
from dataclasses import dataclass, field
from datetime import datetime

from ..checks import dns, gateway, internet
from ..diagnosis import analyze
from ..models import CheckResult, IssueRecord
from .common import (
    BANNER,
    LINE_WIDTH,
    console,
    format_ago,
    render_probes,
)


@dataclass
class WatchState:
    interval: int
    results: list[CheckResult] = field(default_factory=list)
    max_results: int = 100

    def append(self, result: CheckResult) -> None:
        self.results.append(result)
        if len(self.results) > self.max_results:
            self.results = self.results[-self.max_results :]

    @property
    def consecutive_ok(self) -> int:
        count = 0
        for r in reversed(self.results):
            if not r.healthy:
                break
            count += 1
        return count

    @property
    def consecutive_problem(self) -> int:
        count = 0
        for r in reversed(self.results):
            if r.healthy:
                break
            count += 1
        return count

    @property
    def has_had_errors(self) -> bool:
        return any(not r.healthy for r in self.results)

    @property
    def last_error(self) -> CheckResult | None:
        for r in reversed(self.results):
            if not r.healthy:
                return r
        return None

    def issue_history(self) -> list[IssueRecord]:
        return IssueRecord.from_results(self.results)


def _format_issue_line(rec: IssueRecord, timing: str) -> str:
    prefix = "\u26a0" if rec.active else " "
    # Structured columns: source | name | cause | count × timing
    source = f"{rec.source:8s}"
    name = rec.name
    cause = f"({rec.cause})" if rec.cause else ""
    left = f"  {prefix} {source}{name} {cause}"
    right = f"({rec.count}x, {timing})"
    pad = max(1, LINE_WIDTH - len(left) - len(right))
    color = "red" if rec.active else "dim"
    return f"[{color}]{left}{' ' * pad}{right}[/{color}]"


def _render(state: WatchState) -> str:
    """Build the monitoring dashboard output as a rich-markup string."""
    lines: list[str] = []
    lines.append(BANNER)

    latest = state.results[-1]

    lines.append("\n[dim]Is it slow?[/dim]")
    if not latest.healthy:
        lines.append("[red]●[/red] YES!")
    elif state.has_had_errors:
        lines.append("[yellow]●[/yellow] Sorta?")
    else:
        lines.append("[green]●[/green] Nope!")

    history = state.issue_history()
    if history:
        lines.append("\n[dim]Why?[/dim]")
        now = datetime.now()
        for rec in history:
            ago_seconds = (now - rec.last_seen).total_seconds()
            timing = "ongoing" if rec.active else format_ago(ago_seconds)
            lines.append(_format_issue_line(rec, timing))

    lines.append("\n[dim]Details[/dim]")
    lines.append(render_probes(latest))

    lines.append("")
    return "\n".join(lines)


def render(state: WatchState) -> None:
    """Clear screen and draw the dashboard."""
    console.clear()
    console.print(_render(state), end="")


def notify(state: WatchState) -> None:
    """Send notification only on transition from healthy to problem."""
    if len(state.results) < 2:
        return
    curr = state.results[-1]
    if not curr.issues:
        return
    if state.results[-2].healthy:
        worst = curr.issues[0]
        msg = f"yslow: {worst.name}"
        # Terminal bell + OSC 9 desktop notification
        sys.stdout.write(f"\a\033]9;{msg}\033\\")
        sys.stdout.flush()


def watch(interval: int = 30, count: int = 1) -> None:
    """Run monitoring loop. count=0 means infinite."""
    state = WatchState(interval=interval)
    iterations = 0
    try:
        while count == 0 or iterations < count:
            with console.status(
                "[dim]checking why...[/dim]", spinner="dots", spinner_style="dim"
            ):
                now = datetime.now()
                gateway_result = gateway.run()
                internet_results = internet.run()
                dns_results = dns.run()
                issues, alerts = analyze(gateway_result, internet_results, dns_results)
                result = CheckResult(
                    timestamp=now,
                    gateway=gateway_result,
                    internet=internet_results,
                    dns=dns_results,
                    issues=issues,
                    alerts=alerts,
                )
            state.append(result)
            render(state)
            notify(state)
            iterations += 1
            if count == 0 or iterations < count:
                with console.status(
                    f"[dim]rechecking in {interval}s...[/dim]",
                    spinner="dots",
                    spinner_style="dim",
                ):
                    time.sleep(interval)
    except KeyboardInterrupt:
        console.print()
