#!/usr/bin/env python3

"""
Generate release steps script for Lean4 repositories.

This script helps automate the release process for Lean4 and its dependent repositories
by generating step-by-step instructions for updating toolchains, creating tags,
and managing branches.

Usage:
    python3 release_steps.py <version> <repo>

Arguments:
    version: The version to set in the lean-toolchain file (e.g., v4.6.0)
    repo: A substring of the repository name as specified in release_repos.yml

Example:
    python3 release_steps.py v4.6.0 mathlib
    python3 release_steps.py v4.6.0 batt

The script reads repository configurations from release_repos.yml in the same directory.
Each repository may have specific requirements for:
- Branch management
- Toolchain updates
- Dependency updates
- Tagging conventions
- Stable branch handling
"""

import argparse
import yaml
import os
import sys
import re

def load_repos_config(file_path):
    with open(file_path, "r") as f:
        return yaml.safe_load(f)["repositories"]

def find_repo(repo_substring, config):
    pattern = re.compile(re.escape(repo_substring), re.IGNORECASE)
    matching_repos = [r for r in config if pattern.search(r["name"])]
    if not matching_repos:
        print(f"Error: No repository matching '{repo_substring}' found in configuration.")
        sys.exit(1)
    if len(matching_repos) > 1:
        print(f"Error: Multiple repositories matching '{repo_substring}' found in configuration: {', '.join(r['name'] for r in matching_repos)}")
        sys.exit(1)
    return matching_repos[0]

def generate_script(repo, version, config):
    repo_config = find_repo(repo, config)
    repo_name = repo_config['name']
    repo_url = repo_config['url']
    # Extract the last component of the URL, removing the .git extension if present
    repo_dir = repo_url.split('/')[-1].replace('.git', '')
    default_branch = repo_config.get("branch", "main")
    dependencies = repo_config.get("dependencies", [])
    requires_tagging = repo_config.get("toolchain-tag", True)
    has_stable_branch = repo_config.get("stable-branch", True)

    script_lines = [
        f"cd {repo_dir}",
        "git fetch",
        f"git checkout {default_branch} && git pull",
        f"git checkout -b bump_to_{version}",
        f"echo leanprover/lean4:{version} > lean-toolchain",
    ]

    # Special cases for specific repositories
    if repo_name == "repl":
        script_lines.extend([
            "lake update",
            "cd test/Mathlib",
            f"perl -pi -e 's/rev = \"v\\d+\\.\\d+\\.\\d+(-rc\\d+)?\"/rev = \"{version}\"/g' lakefile.toml",
            f"echo leanprover/lean4:{version} > lean-toolchain",
            "lake update",
            "cd ../..",
            "./test.sh"
        ])
    elif dependencies:
        script_lines.append('perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*')
        script_lines.append("lake update")

    script_lines.append("")

    script_lines.extend([
        f'git commit -am "chore: bump toolchain to {version}"',
        ""
    ])

    if re.search(r'rc\d+$', version) and repo_name in ["batteries", "mathlib4"]:
        script_lines.extend([
            "echo 'This repo has nightly-testing infrastructure'",
            f"git merge origin/bump/{version.split('-rc')[0]}",
            "echo 'Please resolve any conflicts.'",
            ""
        ])
    if re.search(r'rc\d+$', version) and repo_name in ["verso", "reference-manual"]:
        script_lines.extend([
            "echo 'This repo does development on nightly-testing: remember to rebase merge the PR.'",
            f"git merge origin/nightly-testing",
            "echo 'Please resolve any conflicts.'",
            ""
        ])
    if repo_name != "Mathlib":
        script_lines.extend([
            "lake build && if lake check-test; then lake test; fi",
            ""
        ])

    script_lines.extend([
        'gh pr create --title "chore: bump toolchain to ' + version + '" --body ""',
        "echo 'Please review the PR and merge or rebase it.'",
        ""
    ])

    return "\n".join(script_lines)

def main():
    parser = argparse.ArgumentParser(
        description="Generate release steps script for Lean4 repositories.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  %(prog)s v4.6.0 mathlib    Generate steps for updating Mathlib to v4.6.0
  %(prog)s v4.6.0 batt       Generate steps for updating Batteries to v4.6.0
  
The script will generate shell commands to:
1. Update the lean-toolchain file
2. Create appropriate branches and commits
3. Create pull requests

(Note that the steps of creating toolchain version tags, and merging these into `stable` branches,
are handled by `script/release_checklist.py`.)
"""
    )
    parser.add_argument("version", help="The version to set in the lean-toolchain file (e.g., v4.6.0)")
    parser.add_argument("repo", help="A substring of the repository name as specified in release_repos.yml")
    args = parser.parse_args()

    config_path = os.path.join(os.path.dirname(__file__), "release_repos.yml")
    config = load_repos_config(config_path)

    script = generate_script(args.repo, args.version, config)
    print(script)

if __name__ == "__main__":
    main()
