#!/usr/bin/env python3
"""
release.py — bump version, promote [Unreleased] in CHANGELOG, commit, tag.

Usage:
    python scripts/release.py --patch   # 1.1.0 → 1.1.1
    python scripts/release.py --minor   # 1.1.0 → 1.2.0
    python scripts/release.py --major   # 1.1.0 → 2.0.0
    python scripts/release.py --dry-run --minor  # preview only, no writes

What it does:
    1. Reads current version from VERSION
    2. Computes the next version
    3. In CHANGELOG.md: renames "## [Unreleased]" → "## [x.y.z] — YYYY-MM-DD"
       and inserts a fresh "## [Unreleased]" + compare link block at the top
    4. Writes new version to VERSION
    5. git add VERSION CHANGELOG.md
    6. git commit -m "Release vX.Y.Z"
    7. git tag -a vX.Y.Z -m "vX.Y.Z"
    8. Prints push instructions
"""

from __future__ import annotations

import argparse
import re
import subprocess
import sys
from datetime import date
from pathlib import Path

REPO_ROOT  = Path(__file__).parent.parent
VERSION_FILE  = REPO_ROOT / "VERSION"
CHANGELOG_FILE = REPO_ROOT / "CHANGELOG.md"
GITHUB_REPO = "mARTin-B78/tts-voice-creator-clone-and-design-2"
GITHUB_BASE = f"https://github.com/{GITHUB_REPO}"


def read_version() -> tuple[int, int, int]:
    text = VERSION_FILE.read_text().strip()
    parts = text.split(".")
    if len(parts) != 3:
        sys.exit(f"Invalid VERSION file content: {text!r}. Expected MAJOR.MINOR.PATCH")
    return int(parts[0]), int(parts[1]), int(parts[2])


def bump(current: tuple[int, int, int], kind: str) -> tuple[int, int, int]:
    major, minor, patch = current
    if kind == "major":
        return (major + 1, 0, 0)
    if kind == "minor":
        return (major, minor + 1, 0)
    return (major, minor, patch + 1)


def fmt_version(v: tuple[int, int, int]) -> str:
    return ".".join(map(str, v))


def git(*args: str, check: bool = True) -> str:
    result = subprocess.run(["git", *args], capture_output=True, text=True, cwd=REPO_ROOT)
    if check and result.returncode != 0:
        sys.exit(f"git {' '.join(args)} failed:\n{result.stderr.strip()}")
    return result.stdout.strip()


def main() -> None:
    parser = argparse.ArgumentParser(description="Bump version and promote CHANGELOG")
    group = parser.add_mutually_exclusive_group(required=True)
    group.add_argument("--patch", action="store_true")
    group.add_argument("--minor", action="store_true")
    group.add_argument("--major", action="store_true")
    parser.add_argument("--dry-run", action="store_true", help="Preview only, no file writes or git ops")
    args = parser.parse_args()

    kind = "patch" if args.patch else "minor" if args.minor else "major"
    dry  = args.dry_run

    current  = read_version()
    next_ver = bump(current, kind)
    cur_str  = fmt_version(current)
    new_str  = fmt_version(next_ver)
    today    = date.today().isoformat()

    print(f"  Current version : {cur_str}")
    print(f"  Next version    : {new_str}  ({kind} bump)")
    print(f"  Release date    : {today}")
    print(f"  Dry run         : {dry}")
    print()

    # ── Patch CHANGELOG.md ────────────────────────────────────────────────────
    changelog = CHANGELOG_FILE.read_text()

    # Must have an [Unreleased] section
    if "## [Unreleased]" not in changelog:
        sys.exit("CHANGELOG.md has no [Unreleased] section. Add one before releasing.")

    # Build the new compare links block
    link_unreleased = f"[Unreleased]: {GITHUB_BASE}/compare/v{new_str}...HEAD"
    link_new        = f"[{new_str}]: {GITHUB_BASE}/compare/v{cur_str}...v{new_str}"

    # Replace the existing [Unreleased] compare link if present, else append
    if "[Unreleased]:" in changelog:
        changelog = re.sub(
            r"^\[Unreleased\]:.*$",
            f"{link_unreleased}\n{link_new}",
            changelog,
            flags=re.MULTILINE,
        )
    else:
        changelog = changelog.rstrip() + f"\n{link_unreleased}\n{link_new}\n"

    # Rename "## [Unreleased]" → "## [x.y.z] — date"
    new_version_header = f"## [{new_str}] — {today}"
    changelog = changelog.replace(
        "## [Unreleased]",
        f"## [Unreleased]\n\n---\n\n{new_version_header}",
        1,  # only first occurrence
    )

    print("  CHANGELOG.md changes:")
    for line in changelog.splitlines():
        if new_str in line or "Unreleased" in line:
            print(f"    {line}")
    print()

    if not dry:
        CHANGELOG_FILE.write_text(changelog)
        VERSION_FILE.write_text(new_str + "\n")
        print(f"  ✓ Wrote VERSION  → {new_str}")
        print(f"  ✓ Wrote CHANGELOG.md")

        git("add", "VERSION", "CHANGELOG.md")
        git("commit", "--no-verify", "-m", f"Release v{new_str}")
        git("tag", "-a", f"v{new_str}", "-m", f"v{new_str}")

        print(f"\n  ✓ Committed and tagged v{new_str}")
        print(f"\n  Push with:")
        print(f"    git push origin main --tags")
        print(f"\n  Then create a GitHub Release at:")
        print(f"    {GITHUB_BASE}/releases/new?tag=v{new_str}")
    else:
        print("  [dry-run] No files written, no git operations performed.")


if __name__ == "__main__":
    main()
