"""export_hub_manifest — genera el TSV sidecar para app_hub_launcher."""

from __future__ import annotations

import os
import sqlite3
import sys
from pathlib import Path
from typing import Any


def _read_frontmatter(md_path: Path) -> dict[str, Any]:
    """Parse YAML frontmatter from a .md file. Returns {} on any error."""
    try:
        import yaml  # PyYAML — available in python/.venv

        text = md_path.read_text(encoding="utf-8")
        if not text.startswith("---"):
            return {}
        # Find the closing ---
        end = text.find("\n---", 3)
        if end == -1:
            return {}
        yaml_block = text[3:end].strip()
        data = yaml.safe_load(yaml_block)
        return data if isinstance(data, dict) else {}
    except Exception as exc:
        print(f"[export_hub_manifest] WARN: could not parse {md_path}: {exc}", file=sys.stderr)
        return {}


def _snake_to_display(name: str) -> str:
    """Convert snake_case name to Title Case With Spaces.

    Examples:
        graph_explorer   -> Graph Explorer
        dag_engine_ui    -> Dag Engine Ui
        app_hub_launcher -> App Hub Launcher
    """
    return " ".join(part.capitalize() for part in name.split("_"))


def export_hub_manifest(out_path: str, *, registry_root: str | None = None) -> dict:
    """Generate TSV sidecar manifest for app_hub_launcher.

    Queries registry.db for all cpp/imgui apps, reads their app.md
    frontmatter to extract name, description and accent color, then
    writes a UTF-8 TSV to out_path.

    Args:
        out_path: Destination path for the TSV manifest file.
        registry_root: Path to the fn_registry root directory.
            Defaults to FN_REGISTRY_ROOT env var or repo root derived from file location.

    Returns:
        {"ok": True, "count": N, "out_path": "<abs_path>"}
    """
    root = Path(
        registry_root
        or os.environ.get("FN_REGISTRY_ROOT")
        or Path(__file__).resolve().parents[3]
    ).resolve()

    db_path = root / "registry.db"
    if not db_path.exists():
        raise FileNotFoundError(f"registry.db not found at {db_path}")

    con = sqlite3.connect(str(db_path))
    con.row_factory = sqlite3.Row
    try:
        rows = con.execute(
            "SELECT id, name, dir_path FROM apps WHERE lang='cpp' AND framework='imgui' ORDER BY name"
        ).fetchall()
    finally:
        con.close()

    DEFAULT_ACCENT = "#64748b"
    TSV_HEADER = "name\tdisplay_name\tdescription\taccent_hex\n"

    lines: list[str] = [TSV_HEADER]
    count = 0

    for row in rows:
        app_name: str = row["name"]
        dir_path: str = row["dir_path"]

        # Derive defaults in case app.md is missing / malformed
        display_name = _snake_to_display(app_name)
        description = ""
        accent_hex = DEFAULT_ACCENT

        md_path = root / dir_path / "app.md"
        if md_path.exists():
            fm = _read_frontmatter(md_path)
            if fm:
                description = fm.get("description", "") or ""
                icon_block = fm.get("icon")
                if isinstance(icon_block, dict):
                    accent_hex = icon_block.get("accent", DEFAULT_ACCENT) or DEFAULT_ACCENT
            else:
                print(
                    f"[export_hub_manifest] WARN: empty/malformed frontmatter in {md_path}",
                    file=sys.stderr,
                )
        else:
            print(
                f"[export_hub_manifest] WARN: app.md missing for {app_name} at {md_path}",
                file=sys.stderr,
            )

        # Sanitize: TSV values must not contain tabs or newlines
        def clean(s: str) -> str:
            return s.replace("\t", " ").replace("\n", " ").replace("\r", "")

        lines.append(
            f"{clean(app_name)}\t{clean(display_name)}\t{clean(description)}\t{clean(accent_hex)}\n"
        )
        count += 1

    out = Path(out_path).resolve()
    out.parent.mkdir(parents=True, exist_ok=True)
    out.write_text("".join(lines), encoding="utf-8")

    return {"ok": True, "count": count, "out_path": str(out)}


if __name__ == "__main__":
    import argparse
    import json

    parser = argparse.ArgumentParser(
        description="Export hub manifest TSV for app_hub_launcher."
    )
    parser.add_argument("out_path", help="Destination .tsv file path")
    parser.add_argument(
        "--registry-root",
        default=None,
        help="Path to fn_registry root (default: FN_REGISTRY_ROOT env or repo root derived from file location)",
    )
    args = parser.parse_args()

    result = export_hub_manifest(args.out_path, registry_root=args.registry_root)
    print(json.dumps(result, indent=2))
