#!/usr/bin/env python3
"""Report readable length diagnostics for LaTeX resume bullets.

This helper has no target bands and no page-fill logic. Rendered character and
word counts are observations; they do not determine whether a bullet is good.

Usage:
  python resume_builder/helpers/char_count.py "\\item Built ..."
  python resume_builder/helpers/char_count.py output/Role/resume.tex
  python resume_builder/helpers/char_count.py --raw "bullet text"
"""

from __future__ import annotations

import argparse
import re
import sys
from pathlib import Path


def strip_latex(text: str) -> str:
    """Approximate reader-visible text without imposing layout targets."""
    text = re.sub(r"\\item\s*(\[\s*\])?\s*", "", text)
    text = re.sub(r"\\href\{[^}]*\}\{([^}]*)\}", r"\1", text)
    for command in ("textbf", "textit", "underline", "emph", "ce"):
        text = re.sub(rf"\\{command}\{{([^}}]*)\}}", r"\1", text)
    text = re.sub(r"\$\^\{?\\circ\}?\$", "°", text)
    text = re.sub(r"\$\^\{([^}]*)\}\$", r"\1", text)
    text = re.sub(r"\$\^(.)\$", r"\1", text)
    text = text.replace("$\\sim$", "~").replace("\\sim", "~")
    text = text.replace("---", "—").replace("--", "–")
    text = text.replace("\\&", "&").replace("\\%", "%")
    text = re.sub(r"\\[A-Za-z]+\s*", "", text)
    text = text.replace("$", "").replace("{", "").replace("}", "")
    return re.sub(r"\s+", " ", text).strip()


def extract_items(source: str) -> list[str]:
    """Extract item bodies, including wrapped source lines."""
    items: list[str] = []
    current: list[str] = []
    for line in source.splitlines():
        stripped = line.strip()
        if stripped.startswith("\\item"):
            if current:
                items.append(" ".join(current))
            current = [stripped]
        elif current and not stripped.startswith("\\end{itemize}"):
            current.append(stripped)
        elif current:
            items.append(" ".join(current))
            current = []
    if current:
        items.append(" ".join(current))
    return items


def diagnose(raw: str) -> tuple[str, int, int, int]:
    rendered = strip_latex(raw)
    words = re.findall(r"\b[\w+#./-]+\b", rendered, flags=re.UNICODE)
    clauses = len(re.findall(r"[;:]|\s—\s", rendered)) + 1 if rendered else 0
    return rendered, len(rendered), len(words), clauses


def format_report(raw: str) -> str:
    rendered, characters, words, clauses = diagnose(raw)
    note = ""
    if words > 35 or clauses > 3:
        note = "\n  Review: potentially dense; check whether it contains multiple accomplishments."
    return (
        f"  {words} words | {characters} rendered characters | {clauses} clause(s)\n"
        f"  Rendered: {rendered}{note}"
    )


def main() -> None:
    parser = argparse.ArgumentParser(description="Report LaTeX bullet length diagnostics")
    parser.add_argument("input", nargs="?", help="Bullet text or .tex file")
    parser.add_argument("--raw", action="store_true", help="Output rendered character count only")
    args = parser.parse_args()

    if args.input and args.input.endswith(".tex") and Path(args.input).is_file():
        items = extract_items(Path(args.input).read_text(encoding="utf-8"))
        if not items:
            print("No \\item bullets found.")
            return
        for index, item in enumerate(items, 1):
            if args.raw:
                print(diagnose(item)[1])
            else:
                print(f"Bullet {index}:\n{format_report(item)}\n")
        return

    raw = args.input if args.input is not None else sys.stdin.read().strip()
    if not raw:
        parser.error("provide bullet text, a .tex file, or stdin")
    print(diagnose(raw)[1] if args.raw else format_report(raw))


if __name__ == "__main__":
    main()
