"""Test service s-expression page components."""
from __future__ import annotations

import os
from datetime import datetime

from shared.sx.jinja_bridge import load_service_components
from shared.sx.helpers import (
    sx_call, SxExpr,
    root_header_sx, full_page_sx, header_child_sx,
)

# Load test-specific .sx components at import time
load_service_components(os.path.dirname(os.path.dirname(__file__)))


def _format_time(ts: float | None) -> str:
    """Format a unix timestamp for display."""
    if not ts:
        return "never"
    return datetime.fromtimestamp(ts).strftime("%-d %b %Y, %H:%M:%S")


# ---------------------------------------------------------------------------
# Menu / header
# ---------------------------------------------------------------------------

_FILTER_MAP = {
    "passed": "passed",
    "failed": "failed",
    "errors": "error",
    "skipped": "skipped",
}


def _filter_tests(tests: list[dict], active_filter: str | None,
                   active_service: str | None) -> list[dict]:
    """Filter tests by outcome and/or service."""
    from runner import _service_from_nodeid
    filtered = tests
    if active_filter and active_filter in _FILTER_MAP:
        outcome = _FILTER_MAP[active_filter]
        filtered = [t for t in filtered if t["outcome"] == outcome]
    if active_service:
        filtered = [t for t in filtered if _service_from_nodeid(t["nodeid"]) == active_service]
    return filtered


# ---------------------------------------------------------------------------
# Results partial
# ---------------------------------------------------------------------------

def test_detail_sx(test: dict) -> str:
    """Return s-expression wire format for a test detail view."""
    inner = sx_call(
        "test-detail",
        nodeid=test["nodeid"],
        outcome=test["outcome"],
        duration=str(test["duration"]),
        longrepr=test.get("longrepr", ""),
    )
    return (
        f'(section :id "main-panel"'
        f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
        f' {inner})'
    )


# ---------------------------------------------------------------------------
# Sx-native versions — return sx source (not HTML)
# ---------------------------------------------------------------------------

def _test_header_sx(ctx: dict, active_service: str | None = None) -> str:
    """Build the Tests menu-row as sx call."""
    nav = _service_nav_sx(ctx, active_service)
    return sx_call("menu-row-sx",
        id="test-row", level=1, colour="sky",
        link_href="/", link_label="Tests", icon="fa fa-flask",
        nav=SxExpr(nav),
        child_id="test-header-child",
    )


def _service_nav_sx(ctx: dict, active_service: str | None = None) -> str:
    """Service filter nav as sx."""
    from runner import _SERVICE_ORDER
    parts = []
    parts.append(sx_call("nav-link",
        href="/", label="all",
        is_selected="true" if not active_service else None,
        select_colours="aria-selected:bg-sky-200 aria-selected:text-sky-900",
    ))
    for svc in _SERVICE_ORDER:
        parts.append(sx_call("nav-link",
            href=f"/?service={svc}", label=svc,
            is_selected="true" if active_service == svc else None,
            select_colours="aria-selected:bg-sky-200 aria-selected:text-sky-900",
        ))
    return "(<> " + " ".join(parts) + ")"


def _header_stack_sx(ctx: dict, active_service: str | None = None) -> str:
    """Full header stack as sx."""
    hdr = root_header_sx(ctx)
    inner = _test_header_sx(ctx, active_service)
    child = header_child_sx(inner)
    return "(<> " + hdr + " " + child + ")"


def _test_rows_sx(tests: list[dict]) -> str:
    """Render all test result rows as sx."""
    parts = []
    for t in tests:
        parts.append(sx_call("test-row",
            nodeid=t["nodeid"],
            outcome=t["outcome"],
            duration=str(t["duration"]),
            longrepr=t.get("longrepr", ""),
        ))
    return "(<> " + " ".join(parts) + ")"


def _grouped_rows_sx(tests: list[dict]) -> str:
    """Test rows grouped by service as sx."""
    from runner import group_tests_by_service
    sections = group_tests_by_service(tests)
    parts = []
    for sec in sections:
        parts.append(sx_call("test-service-header",
            service=sec["service"],
            total=str(sec["total"]),
            passed=str(sec["passed"]),
            failed=str(sec["failed"]),
        ))
        parts.append(_test_rows_sx(sec["tests"]))
    return "(<> " + " ".join(parts) + ")"


def _results_partial_sx(result: dict | None, running: bool, csrf: str,
                           active_filter: str | None = None,
                           active_service: str | None = None) -> str:
    """Results section as sx."""
    if running and not result:
        summary = sx_call("test-summary",
            status="running", passed="0", failed="0", errors="0",
            skipped="0", total="0", duration="...",
            last_run="in progress", running=True, csrf=csrf,
            active_filter=active_filter,
        )
        return "(<> " + summary + " " + sx_call("test-running-indicator") + ")"

    if not result:
        summary = sx_call("test-summary",
            status=None, passed="0", failed="0", errors="0",
            skipped="0", total="0", duration="0",
            last_run="never", running=running, csrf=csrf,
            active_filter=active_filter,
        )
        return "(<> " + summary + " " + sx_call("test-no-results") + ")"

    status = "running" if running else result["status"]
    summary = sx_call("test-summary",
        status=status,
        passed=str(result["passed"]),
        failed=str(result["failed"]),
        errors=str(result["errors"]),
        skipped=str(result.get("skipped", 0)),
        total=str(result["total"]),
        duration=str(result["duration"]),
        last_run=_format_time(result["finished_at"]) if not running else "in progress",
        running=running,
        csrf=csrf,
        active_filter=active_filter,
    )

    if running:
        return "(<> " + summary + " " + sx_call("test-running-indicator") + ")"

    tests = result.get("tests", [])
    tests = _filter_tests(tests, active_filter, active_service)
    if not tests:
        return "(<> " + summary + " " + sx_call("test-no-results") + ")"

    has_failures = result["failed"] > 0 or result["errors"] > 0
    rows = _grouped_rows_sx(tests)
    table = sx_call("test-results-table",
        rows=SxExpr(rows),
        has_failures=str(has_failures).lower(),
    )
    return "(<> " + summary + " " + table + ")"


def _wrap_results_div_sx(inner: str, running: bool) -> str:
    """Wrap results in a div with HTMX polling (sx)."""
    attrs = ':id "test-results" :class "space-y-6 p-4"'
    if running:
        attrs += ' :sx-get "/results" :sx-trigger "every 2s" :sx-swap "outerHTML"'
    return f'(div {attrs} {inner})'


async def render_dashboard_page_sx(ctx: dict, result: dict | None,
                                      running: bool, csrf: str,
                                      active_filter: str | None = None,
                                      active_service: str | None = None) -> str:
    """Full page: test dashboard (sx wire format)."""
    hdr = _header_stack_sx(ctx, active_service)
    inner = _results_partial_sx(result, running, csrf, active_filter, active_service)
    content = _wrap_results_div_sx(inner, running)
    return full_page_sx(ctx, header_rows=hdr, content=content)


async def render_results_partial_sx(result: dict | None, running: bool,
                                       csrf: str,
                                       active_filter: str | None = None,
                                       active_service: str | None = None) -> str:
    """HTMX partial: results section (sx wire format)."""
    inner = _results_partial_sx(result, running, csrf, active_filter, active_service)
    return _wrap_results_div_sx(inner, running)


async def render_test_detail_page_sx(ctx: dict, test: dict) -> str:
    """Full page: test detail (sx wire format)."""
    root_hdr = root_header_sx(ctx)
    test_row = _test_header_sx(ctx)
    detail_row = sx_call("menu-row-sx",
        id="test-detail-row", level=2, colour="sky",
        link_href=f"/test/{test['nodeid']}",
        link_label=test["nodeid"].rsplit("::", 1)[-1],
    )
    inner = "(<> " + test_row + " " + header_child_sx(detail_row, id="test-header-child") + ")"
    hdr = "(<> " + root_hdr + " " + header_child_sx(inner) + ")"
    content = sx_call("test-detail",
        nodeid=test["nodeid"],
        outcome=test["outcome"],
        duration=str(test["duration"]),
        longrepr=test.get("longrepr", ""),
    )
    return full_page_sx(ctx, header_rows=hdr, content=content)
