#!/usr/bin/env python3
"""Cut a new release: collect DONE items from Backlog into a new Version section.

Usage:
    poetry run python scripts/release.py major
    poetry run python scripts/release.py minor
"""

import re
import subprocess
import sys
from pathlib import Path

PROJECT_FILE = Path("PROJECT.org")
PYPROJECT_FILE = Path("pyproject.toml")

BACKLOG_RE = re.compile(r"^\* Backlog\s+\[(\d+)/(\d+)\](.*)$")
VERSION_RE = re.compile(r"^\* Version\s+(\d+\.\d+)\s+\[\d+/\d+\]")
DONE_HEADER_RE = re.compile(r"^(\*\* DONE\s+)(.*)$")
ITEM_HEADER_RE = re.compile(r"^\*\* ")


def parse_done_line(line):
    """Extract a clean title from a ** DONE line, stripping priority and tags."""
    rest = line[8:].strip()  # remove "** DONE "
    # strip priority marker like [#A]
    rest = re.sub(r"^\[#[A-C]\]\s+", "", rest, count=1)
    # strip org-mode tags at end (space-colon-tags)
    rest = re.sub(r"\s+:\S.*:\s*$", "", rest)
    return rest


def bump_version(current_major, current_minor, kind):
    if kind == "major":
        return current_major + 1, 0
    elif kind == "minor":
        return current_major, current_minor + 1
    else:
        raise ValueError(f"Unknown bump kind: {kind}")


def main():
    if len(sys.argv) < 2 or sys.argv[1] not in ("major", "minor"):
        print(f"Usage: {sys.argv[0]} <major|minor>", file=sys.stderr)
        sys.exit(1)

    kind = sys.argv[1]

    lines = PROJECT_FILE.read_text().splitlines(keepends=True)

    # ---------------------------------------------------------------
    # 1. Identify top-level sections
    # ---------------------------------------------------------------
    section_starts = []
    for i, line in enumerate(lines):
        if line.startswith("* ") and not line.startswith("** "):
            section_starts.append(i)
    section_starts.append(len(lines))

    backlog_idx = None
    version_idx = None

    for idx, start in enumerate(section_starts[:-1]):
        header = lines[start].strip()
        if header.startswith("* Backlog"):
            backlog_idx = idx
        if header.startswith("* Version"):
            version_idx = idx  # last occurrence wins

    if backlog_idx is None:
        print("ERROR: no Backlog section found", file=sys.stderr)
        sys.exit(1)
    if version_idx is None:
        print("ERROR: no Version section found", file=sys.stderr)
        sys.exit(1)

    backlog_start = section_starts[backlog_idx]
    backlog_end = section_starts[backlog_idx + 1]

    # Find the newest Version section (first after Backlog) that matches
    # our expected format (e.g. "37.0" not "0.11.4").
    version_start = None
    for idx in range(backlog_idx + 1, version_idx + 1):
        header = lines[section_starts[idx]].strip()
        if VERSION_RE.match(header):
            version_start = section_starts[idx]
            break

    if version_start is None:
        print("ERROR: no parseable Version header found", file=sys.stderr)
        sys.exit(1)

    version_header = lines[version_start].strip()

    # ---------------------------------------------------------------
    # 2. Parse current version from the newest * Version header
    # ---------------------------------------------------------------
    vm = VERSION_RE.match(version_header)
    current_version = vm.group(1)
    major_str, minor_str = current_version.split(".")
    current_major = int(major_str)
    current_minor = int(minor_str)
    new_major, new_minor = bump_version(current_major, current_minor, kind)
    new_version = f"{new_major}.{new_minor}"

    # ---------------------------------------------------------------
    # 3. Collect ** DONE items from the Backlog section
    # ---------------------------------------------------------------
    backlog_lines = lines[backlog_start:backlog_end]

    # Split Backlog into items at each ** line (skip the section header)
    items = []  # list of (start_idx, end_idx, is_done)
    item_start = None
    for i in range(1, len(backlog_lines)):
        if ITEM_HEADER_RE.match(backlog_lines[i]):
            if item_start is not None:
                items.append((item_start, i, backlog_lines[item_start].startswith("** DONE")))
            item_start = i
    if item_start is not None:
        items.append((item_start, len(backlog_lines), backlog_lines[item_start].startswith("** DONE")))

    done_items = [(s, e) for s, e, is_done in items if is_done]
    kept_items = [(s, e) for s, e, is_done in items if not is_done]

    if not done_items:
        print("No DONE items found in Backlog — nothing to release.")
        sys.exit(1)

    # ---------------------------------------------------------------
    # 4. Build the new Version section text
    # ---------------------------------------------------------------
    version_section_lines = [f"* Version {new_version} [{len(done_items)}/{len(done_items)}]\n"]
    for s, e in done_items:
        version_section_lines.extend(backlog_lines[s:e])

    # ---------------------------------------------------------------
    # 5. Build updated Backlog section
    # ---------------------------------------------------------------
    backlog_header_line = backlog_lines[0]
    bm = BACKLOG_RE.match(backlog_header_line.strip())
    if not bm:
        print(f"ERROR: could not parse backlog header: {backlog_header_line!r}", file=sys.stderr)
        sys.exit(1)
    done_count = int(bm.group(1))
    total_count = int(bm.group(2))
    tags = bm.group(3)

    new_done = done_count - len(done_items)
    new_total = total_count - len(done_items)
    new_backlog_header = f"* Backlog [{new_done}/{new_total}]{tags}\n"

    backlog_body = []
    for s, e in kept_items:
        backlog_body.extend(backlog_lines[s:e])

    # ---------------------------------------------------------------
    # 6. Assemble the new file
    # ---------------------------------------------------------------
    before_backlog = lines[:backlog_start]
    after_backlog = lines[backlog_end:version_start]

    # Everything from the first Version section onwards
    from_version = lines[version_start:]

    output = (
        before_backlog
        + [new_backlog_header]
        + backlog_body
        + version_section_lines
        + ["\n"]
        + after_backlog
        + from_version
    )

    # ---------------------------------------------------------------
    # 7. Update pyproject.toml
    # ---------------------------------------------------------------
    pyproject = PYPROJECT_FILE.read_text()
    pyproject = re.sub(
        r'^version = "[\d.]+"',
        f'version = "{new_version}"',
        pyproject,
        count=1,
        flags=re.MULTILINE,
    )

    # ---------------------------------------------------------------
    # 8. Write files
    # ---------------------------------------------------------------
    PROJECT_FILE.write_text("".join(output))
    PYPROJECT_FILE.write_text(pyproject)

    # ---------------------------------------------------------------
    # 9. Build commit body from done item titles
    # ---------------------------------------------------------------
    commit_lines = []
    for s, e in done_items:
        title = parse_done_line(backlog_lines[s])
        if title:
            commit_lines.append(f"- {title}")

    commit_body = "\n".join(commit_lines)
    commit_message = f"[release] Bump to version {new_version}\n\n{commit_body}"

    # ---------------------------------------------------------------
    # 10. Git commit + tag
    # ---------------------------------------------------------------
    subprocess.run(["git", "add", str(PROJECT_FILE), str(PYPROJECT_FILE)], check=True)
    subprocess.run(["git", "commit", "-m", commit_message], check=True)
    subprocess.run(["git", "tag", new_version], check=True)

    print(f"\nReleased v{new_version} — tag {new_version} created.")
    print(f"Moved {len(done_items)} DONE item(s) from Backlog to Version section.")


if __name__ == "__main__":
    main()
