#!/usr/bin/env python3
"""Genera un flowchart Mermaid documentale da un manifest JSON."""

from __future__ import annotations

import argparse
import json
import re
import sys
from pathlib import Path
from typing import Any


def node_id(value: str, used: set[str]) -> str:
    base = re.sub(r"[^A-Za-z0-9_]", "_", value)
    if not base or base[0].isdigit():
        base = f"n_{base}"
    candidate = base
    suffix = 2
    while candidate in used:
        candidate = f"{base}_{suffix}"
        suffix += 1
    used.add(candidate)
    return candidate


def safe_label(value: Any) -> str:
    text = str(value).replace("\n", " ").replace('"', "'")
    return re.sub(r"[<>]", "", text)[:120]


def shape(identifier: str, label: str, state_type: str) -> str:
    if state_type == "decision":
        return f'{identifier}{{"{label}"}}'
    if state_type == "approval":
        return f'{identifier}{{{{"{label}"}}}}'
    if state_type == "end":
        return f'{identifier}(("{label}"))'
    if state_type == "error":
        return f'{identifier}[\\"{label}"\\]'
    return f'{identifier}["{label}"]'


def render_mermaid(data: dict[str, Any]) -> str:
    states = [state for state in data.get("states", []) if isinstance(state, dict) and isinstance(state.get("id"), str)]
    used: set[str] = set()
    identifiers = {state["id"]: node_id(state["id"], used) for state in states}
    lines = ["flowchart TD"]
    for state in states:
        label = safe_label(state.get("label", state["id"]))
        lines.append(f"    {shape(identifiers[state['id']], label, str(state.get('type', 'action')))}")
    for state in states:
        source = identifiers[state["id"]]
        for target in state.get("next", []):
            if target in identifiers:
                lines.append(f"    {source} --> {identifiers[target]}")
    start = data.get("trigger", {}).get("start_state") if isinstance(data.get("trigger"), dict) else None
    if start in identifiers:
        lines.append("    classDef start fill:#f4bd3f,stroke:#171713,color:#171713;")
        lines.append(f"    class {identifiers[start]} start;")
    approval_ids = [identifiers[state["id"]] for state in states if state.get("type") == "approval"]
    if approval_ids:
        lines.append("    classDef approval fill:#f26b4f,stroke:#171713,color:#171713;")
        lines.append(f"    class {','.join(approval_ids)} approval;")
    return "\n".join(lines) + "\n"


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("manifest", type=Path)
    parser.add_argument("--output", type=Path)
    args = parser.parse_args()
    try:
        data = json.loads(args.manifest.read_text(encoding="utf-8"))
    except (OSError, json.JSONDecodeError) as exc:
        print(f"Impossibile leggere il manifest: {exc}", file=sys.stderr)
        return 2
    if not isinstance(data, dict):
        print("La radice deve essere un oggetto JSON.", file=sys.stderr)
        return 2
    output = render_mermaid(data)
    if args.output:
        args.output.parent.mkdir(parents=True, exist_ok=True)
        args.output.write_text(output, encoding="utf-8")
        print(f"Diagramma scritto in {args.output}")
    else:
        print(output, end="")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
