from __future__ import annotations

import json
from collections import OrderedDict

from autosana_cli.models import DoctorCheck, DoctorReport, Session, SessionHealth


def json_line(payload: dict) -> str:
    return json.dumps(payload, separators=(",", ":"), sort_keys=False)


def format_up_summary(session: Session, *, detached: bool) -> str:
    mode = "detached" if detached else "foreground"
    lines = [
        "Session ready",
        f"  session_id: {session.session_id}",
        f"  platform:   {session.platform.value}",
        f"  device:     {session.device_name}",
    ]
    if session.app_detection == "ok" and session.installed_apps:
        lines.append(f"  apps:       {len(session.installed_apps)} user app(s) detected")
        for app_info in session.installed_apps[:10]:
            lines.append(f"              - {app_info.name} ({app_info.bundle_id})")
    elif session.app_detection == "failed":
        lines.append("  apps:       detection failed (will ask during test setup)")
    elif session.app_detection == "none_found":
        lines.append("  apps:       none found — install your app first")
    lines.extend(
        [
            f"  appium:     http://127.0.0.1:{session.appium_port}",
            f"  tunnel:     {session.tunnel_url}",
            f"  mode:       {mode}",
            f"  appium log: {session.appium_log_path}",
            f"  tunnel log: {session.tunnel_log_path}",
        ]
    )
    return "\n".join(lines)


def format_status(health_checks: list[SessionHealth]) -> str:
    if not health_checks:
        return "No active Autosana sessions."

    lines = []
    for health in health_checks:
        lines.extend(
            [
                f"{health.session.session_id} [{health.status}]",
                f"  platform: {health.session.platform.value}",
                f"  device:   {health.session.device_name}",
                f"  tunnel:   {health.session.tunnel_url}",
                f"  appium:   http://127.0.0.1:{health.session.appium_port}",
            ]
        )
        if health.issues:
            lines.append(f"  issues:   {', '.join(health.issues)}")
    return "\n".join(lines)


def _group_checks(checks: list[DoctorCheck]) -> OrderedDict[str, list[DoctorCheck]]:
    """Group checks preserving insertion order, with a stable group ordering."""
    GROUP_ORDER = ["Core", "iOS", "Android"]
    groups: OrderedDict[str, list[DoctorCheck]] = OrderedDict()
    for g in GROUP_ORDER:
        for check in checks:
            if check.group == g:
                groups.setdefault(g, []).append(check)
    # Catch any groups not in GROUP_ORDER
    for check in checks:
        if check.group not in GROUP_ORDER:
            groups.setdefault(check.group, []).append(check)
    return groups


def format_doctor(report: DoctorReport) -> str:
    """Rich-formatted doctor output grouped by platform with colors."""
    try:
        return _format_doctor_rich(report)
    except Exception:
        return _format_doctor_plain(report)


def _format_doctor_rich(report: DoctorReport) -> str:
    from io import StringIO

    from rich.console import Console
    from rich.table import Table
    from rich.text import Text

    buf = StringIO()
    console = Console(file=buf, force_terminal=True, width=100)

    # Header
    if report.ok:
        console.print("\n  [bold green]All checks passed[/bold green]\n")
    else:
        failed = sum(1 for c in report.checks if not c.ok)
        fixable = sum(1 for c in report.checks if not c.ok and c.fixable)
        console.print(f"\n  [bold red]{failed} issue(s) found[/bold red]")
        if fixable:
            console.print(f"  [dim]Run [bold]autosana doctor --fix[/bold] to auto-fix {fixable} of them[/dim]\n")
        else:
            console.print()

    groups = _group_checks(report.checks)
    GROUP_ICONS = {"Core": "gear", "iOS": "iPhone", "Android": "robot"}

    for group_name, checks in groups.items():
        icon = GROUP_ICONS.get(group_name, "")
        table = Table(
            title=f"  {icon}  {group_name}" if icon else f"  {group_name}",
            title_style="bold",
            show_header=False,
            box=None,
            padding=(0, 2),
            expand=False,
        )
        table.add_column("status", width=4, justify="center")
        table.add_column("name", min_width=20, style="bold")
        table.add_column("detail")

        for check in checks:
            if check.ok:
                status = Text("  ✓ ", style="green")
                detail = Text(check.message, style="dim")
            elif check.fixable:
                status = Text("  ✗ ", style="yellow")
                detail = Text(f"{check.message}  ", style="yellow") + Text("(auto-fixable)", style="dim yellow")
            else:
                status = Text("  ✗ ", style="red")
                detail = Text(f"{check.message}  ", style="red") + Text("(manual)", style="dim red")

            table.add_row(status, check.name, detail)

        console.print(table)
        console.print()

    return buf.getvalue().rstrip()


def _format_doctor_plain(report: DoctorReport) -> str:
    """Fallback plain-text output if rich is unavailable."""
    lines = ["Doctor checks"]
    for check in report.checks:
        marker = "ok" if check.ok else "error"
        line = f"  [{marker}] {check.name}: {check.message}"
        if not check.ok and check.fixable:
            line += " (auto-fixable)"
        elif not check.ok:
            line += " (manual fix required)"
        lines.append(line)
    return "\n".join(lines)


def status_payload(health_checks: list[SessionHealth]) -> dict:
    return {"sessions": [health.to_dict() for health in health_checks]}
