#!/usr/bin/env python3
"""Validate CARBON's standalone user-flow library."""

from __future__ import annotations

import json
import re
import sys
from pathlib import Path

from select_flows import select

SKILL_ROOT = Path(__file__).resolve().parents[1]
FLOW_ROOT = SKILL_ROOT / "references" / "flows"
LINK = re.compile(r"\[[^\]]+\]\(([^)#]+)(?:#[^)]+)?\)")
FLOW_KEY = re.compile(r"^\*\*Flow key:\*\* `([^`]+)`$", re.MULTILINE)
DATA_ROW = re.compile(
    r"^\| (?!Data\b|---)([^|]+) \| ([^|]+) \| ([^|]+) \|$", re.MULTILINE
)
STEP_ROW = re.compile(r"^\| (\d+) \| ([^|]+) \| ([^|]+) \|$", re.MULTILINE)
REQUIRED_HEADINGS = [
    "## Outcome",
    "## Actors",
    "## Preconditions and entry points",
    "## Required test data",
    "## Canonical steps",
    "## Alternate paths",
    "## Failure and recovery paths",
    "## Completion oracle",
    "## Evidence to capture",
    "## Product decisions to resolve",
    "## Related CARBON items",
]


def section(source: str, start: str, end: str) -> str:
    return source.split(start, 1)[1].split(end, 1)[0]


def main() -> int:
    errors: list[str] = []
    keys: dict[str, Path] = {}
    data_rows = 0
    step_rows = 0
    flow_files = [
        path for path in sorted(FLOW_ROOT.glob("*/*.md")) if path.name != "index.md"
    ]
    index_files = sorted(FLOW_ROOT.glob("**/index.md"))

    for path in flow_files:
        source = path.read_text(encoding="utf-8")
        relative = path.relative_to(SKILL_ROOT)
        key_match = FLOW_KEY.search(source)
        if not key_match:
            errors.append(f"{relative}: missing flow key")
        else:
            key = key_match.group(1)
            if key != path.stem:
                errors.append(f"{relative}: flow key {key!r} does not match filename")
            if key in keys:
                errors.append(f"{relative}: duplicate flow key {key!r}")
            keys[key] = path
            expected_selection = str(path.relative_to(FLOW_ROOT))
            if expected_selection not in select(key):
                errors.append(
                    f"{relative}: selector does not resolve exact flow key {key!r}"
                )

        if source.count("\n# ") + source.startswith("# ") != 1:
            errors.append(f"{relative}: expected exactly one H1")
        for heading in REQUIRED_HEADINGS:
            if source.count(heading) != 1:
                errors.append(f"{relative}: expected one {heading!r}")
        rows = DATA_ROW.findall(
            section(source, "## Required test data", "## Canonical steps")
        )
        steps = STEP_ROW.findall(
            section(source, "## Canonical steps", "## Alternate paths")
        )
        data_rows += len(rows)
        step_rows += len(steps)
        if len(rows) < 4:
            errors.append(
                f"{relative}: only {len(rows)} required-data rows; minimum is 4"
            )
        if len(steps) < 5:
            errors.append(
                f"{relative}: only {len(steps)} canonical steps; minimum is 5"
            )
        if "Use synthetic, isolated, resettable data." not in source:
            errors.append(f"{relative}: missing synthetic-data safety instruction")
        for target in LINK.findall(source):
            resolved = (path.parent / target).resolve()
            if not resolved.exists():
                errors.append(f"{relative}: missing link target {target}")

    for path in index_files:
        source = path.read_text(encoding="utf-8")
        relative = path.relative_to(SKILL_ROOT)
        for target in LINK.findall(source):
            resolved = (path.parent / target).resolve()
            if not resolved.exists():
                errors.append(f"{relative}: missing link target {target}")

    result = {
        "flow_files": len(flow_files),
        "index_files": len(index_files),
        "flow_keys": len(keys),
        "selector_routes": len(keys),
        "required_data_rows": data_rows,
        "canonical_steps": step_rows,
        "minimum_data_rows": min(
            (
                len(
                    DATA_ROW.findall(
                        section(
                            path.read_text(encoding="utf-8"),
                            "## Required test data",
                            "## Canonical steps",
                        )
                    )
                )
                for path in flow_files
            ),
            default=0,
        ),
        "minimum_steps": min(
            (
                len(
                    STEP_ROW.findall(
                        section(
                            path.read_text(encoding="utf-8"),
                            "## Canonical steps",
                            "## Alternate paths",
                        )
                    )
                )
                for path in flow_files
            ),
            default=0,
        ),
        "errors": errors,
    }
    print(json.dumps(result, indent=2))
    return 1 if errors else 0


if __name__ == "__main__":
    sys.exit(main())
