#!/usr/bin/env python3
"""Generate the Tree of Ascension action-points totals manifest.

Scans docs/**/*.md for Markdown tasklist items (`- [ ]` / `- [x]`), counts
them per page, and writes docs/javascripts/toa-totals.json mapping each
page's site URL -> total task count.

The action-points JS (docs/javascripts/extra.js) fetches this manifest once
on first load so nav badges show correct totals BEFORE a user has visited
every page. Counts are fully static (known from the Markdown), so this has
zero runtime cost — it's a build-time artifact.

Run before `zensical build`:
    python3 main.py
"""

from __future__ import annotations

import json
import re
from pathlib import Path

ROOT = Path(__file__).resolve().parent
DOCS = ROOT / "docs"
OUT = DOCS / "javascripts" / "toa-totals.json"

# Matches a Markdown tasklist item: optional indent, list marker, [ ] or [x].
TASK_RE = re.compile(r"^\s*[-*+]\s+\[[ xX]\]\s+", re.MULTILINE)

# Matches fenced code blocks (``` or ~~~), incl. language hint, non-greedy.
# These contain tasklist *examples* (e.g. the Markdown reference doc) that render
# as plain text, NOT interactive checkboxes — so we strip them before counting.
FENCE_RE = re.compile(r"^([ \t]*)(`{3,}|~{3,}).*?\n.*?^\1\2[ \t]*$", re.MULTILINE | re.DOTALL)


def count_tasks(text: str) -> int:
    """Count real (interactive) tasklist items, excluding fenced code examples."""
    stripped = FENCE_RE.sub("", text)
    return len(TASK_RE.findall(stripped))


def url_for(md_path: Path) -> str:
    """Map a docs/*.md path to its built site URL (directory-style URLs).

    docs/index.md                  -> /
    docs/practices/index.md        -> /practices/
    docs/practices/daily-sadhana.md-> /practices/daily-sadhana/
    """
    rel = md_path.relative_to(DOCS).with_suffix("")
    parts = list(rel.parts)
    if parts and parts[-1] == "index":
        parts = parts[:-1]
    path = "/" + "/".join(parts)
    if not path.endswith("/"):
        path += "/"
    return path


def main() -> None:
    totals: dict[str, int] = {}
    for md in sorted(DOCS.rglob("*.md")):
        text = md.read_text(encoding="utf-8")
        count = count_tasks(text)
        if count:
            totals[url_for(md)] = count

    OUT.parent.mkdir(parents=True, exist_ok=True)
    OUT.write_text(json.dumps(totals, indent=2, sort_keys=True) + "\n", encoding="utf-8")
    print(f"toa-totals: wrote {len(totals)} page(s) -> {OUT.relative_to(ROOT)}")
    for url, n in sorted(totals.items()):
        print(f"  {url}  {n}")


if __name__ == "__main__":
    main()
