"""HTML views for project registry pages (#427, evolved for #635).

Every view renders from :func:`webui.project_registry.project_to_dict`, the
same DTO the ``/api/v1/projects`` JSON responses use, so the HTML console and
the API can never disagree about status or onboarding progress.
"""

from __future__ import annotations

import html
from typing import Any

from webui.layout import render_page
from webui.project_registry import (
    ProjectRecord,
    ProjectRegistry,
    RegistryError,
    project_to_dict,
)

_STATE_LABELS = {
    "complete": "Complete",
    "pending": "Pending",
    "blocked": "Blocked",
    "not_applicable": "Not applicable",
}


def _escape(text: str) -> str:
    return html.escape(text, quote=True)


def _progress_label(summary: dict[str, Any]) -> str:
    total = summary["total"]
    if not total:
        return "no steps"
    label = f"{summary['complete']}/{total} complete"
    if summary["blocked"]:
        label += f", {summary['blocked']} blocked"
    return label


def render_projects_list(registry: ProjectRegistry) -> str:
    rows = []
    for project in registry.projects:
        dto = project_to_dict(project)
        rows.append(
            "<tr>"
            f"<td><a href=\"/projects/{_escape(dto['id'])}\">{_escape(dto['repo_name'])}</a></td>"
            f"<td>{_escape(dto['gitea_owner'])}</td>"
            f"<td>{_escape(dto['remote_host'])}</td>"
            f"<td>{_escape(dto['default_branch'])}</td>"
            f"<td><code>{_escape(dto['status'])}</code></td>"
            f"<td>{_escape(_progress_label(dto['onboarding_summary']))}</td>"
            f"<td><code>{_escape(dto['profiles']['author'])}</code></td>"
            "</tr>"
        )
    table = (
        "<table class=\"registry\">"
        "<thead><tr>"
        "<th>Repository</th><th>Owner</th><th>Remote</th>"
        "<th>Branch</th><th>Status</th><th>Onboarding</th><th>Author profile</th>"
        "</tr></thead>"
        f"<tbody>{''.join(rows)}</tbody></table>"
    )
    body = (
        "<h2>Projects</h2>"
        "<p>Configured repositories managed by the MCP Control Plane.</p>"
        f"<p class=\"meta\">Registry: <code>{_escape(str(registry.source_path))}</code> "
        f"(schema version {registry.schema_version}, "
        f"API {_escape(registry.api_version)})</p>"
        f"{table}"
        "<p><a href=\"/api/v1/projects\">JSON API</a> "
        "(<a href=\"/api/projects\">unversioned alias</a>)</p>"
    )
    return render_page(title="Projects", body_html=body)


def render_project_detail(project: ProjectRecord) -> str:
    dto = project_to_dict(project)
    profile_rows = "".join(
        f"<tr><th>{_escape(role)}</th><td><code>{_escape(name)}</code></td></tr>"
        for role, name in dto["profiles"].items()
    )
    workflow_rows = "".join(
        f"<tr><th>{_escape(key)}</th><td><code>{_escape(path)}</code></td></tr>"
        for key, path in dto["workflow_paths"].items()
    )
    schema_rows = "".join(
        f"<tr><th>{_escape(key)}</th><td><code>{_escape(path)}</code></td></tr>"
        for key, path in dto["schema_paths"].items()
    )
    checklist_items = []
    for index, step in enumerate(dto["onboarding_checklist"], start=1):
        state_label = _STATE_LABELS.get(step["state"], step["state"])
        requirement = "required" if step["required"] else "optional"
        checklist_items.append(
            f"<li class=\"step-{_escape(step['state'])}\">"
            f"<strong>{index}. {_escape(step['title'])}</strong>"
            f" <span class=\"badge\">{_escape(state_label)}</span>"
            f" <span class=\"meta\">({_escape(requirement)})</span>"
            f"<p>{_escape(step['description'])}</p>"
            "</li>"
        )
    checklist_html = (
        "<ol class=\"checklist\">" + "".join(checklist_items) + "</ol>"
        if checklist_items
        else "<p>No onboarding steps defined.</p>"
    )
    summary = dto["onboarding_summary"]
    summary_html = (
        "<p class=\"meta\">Onboarding: "
        f"{_escape(_progress_label(summary))}; required outstanding "
        f"{summary['required_outstanding']}.</p>"
    )
    health = dto["last_seen_health"]
    health_html = (
        "<p class=\"meta\">No health probe recorded (Phase 1 is read-only).</p>"
        if health is None
        else (
            "<table class=\"detail\">"
            f"<tr><th>Status</th><td><code>{_escape(health['status'])}</code></td></tr>"
            f"<tr><th>Checked at</th><td>{_escape(str(health['checked_at'] or 'unknown'))}</td></tr>"
            f"<tr><th>Detail</th><td>{_escape(str(health['detail'] or ''))}</td></tr>"
            "</table>"
        )
    )
    remote_name = dto["remote_name"] or "unset"
    body = (
        f"<h2>{_escape(dto['repo_name'])}</h2>"
        "<p><a href=\"/projects\">← All projects</a></p>"
        "<h3>Identity</h3>"
        "<table class=\"detail\">"
        f"<tr><th>Registry id</th><td><code>{_escape(dto['id'])}</code></td></tr>"
        f"<tr><th>Status</th><td><code>{_escape(dto['status'])}</code></td></tr>"
        f"<tr><th>Gitea owner</th><td>{_escape(dto['gitea_owner'])}</td></tr>"
        f"<tr><th>Repository</th><td><code>{_escape(dto['repo_full_name'])}</code></td></tr>"
        f"<tr><th>Remote name</th><td><code>{_escape(remote_name)}</code></td></tr>"
        f"<tr><th>Remote host</th><td>{_escape(dto['remote_host'])}</td></tr>"
        f"<tr><th>Default branch</th><td><code>{_escape(dto['default_branch'])}</code></td></tr>"
        f"<tr><th>Local checkout</th><td><code>{_escape(dto['local_checkout_path'])}</code></td></tr>"
        "</table>"
        "<h3>Profiles</h3>"
        f"<table class=\"detail\">{profile_rows}</table>"
        "<h3>Workflow paths</h3>"
        f"<table class=\"detail\">{workflow_rows}</table>"
        "<h3>Schema paths</h3>"
        f"<table class=\"detail\">{schema_rows}</table>"
        "<h3>Last seen health</h3>"
        f"{health_html}"
        "<h3>Onboarding checklist</h3>"
        "<p class=\"meta\">Read-only — complete these steps outside the UI.</p>"
        f"{summary_html}"
        f"{checklist_html}"
        f"<p><a href=\"/api/v1/projects/{_escape(dto['id'])}\">JSON detail</a></p>"
    )
    return render_page(title=dto["repo_name"], body_html=body)


def render_registry_error(error: RegistryError) -> str:
    """Render a fail-closed page for an invalid registry."""
    source = str(error.source_path) if error.source_path else "unknown"
    field = error.field_path or "n/a"
    body = (
        "<h2>Project registry unavailable</h2>"
        "<p>The registry failed validation, so the console refuses to render a "
        "partial inventory.</p>"
        "<table class=\"detail\">"
        f"<tr><th>Detail</th><td>{_escape(error.message)}</td></tr>"
        f"<tr><th>Field</th><td><code>{_escape(field)}</code></td></tr>"
        f"<tr><th>Source</th><td><code>{_escape(source)}</code></td></tr>"
        f"<tr><th>Remediation</th><td>{_escape(error.remediation)}</td></tr>"
        "</table>"
    )
    return render_page(title="Project registry unavailable", body_html=body)
