#!/usr/bin/env python3
"""开发分支工作区初始化脚本

用于创建基于远端分支或新建的开发分支工作区。
"""

import argparse
import subprocess
import sys
from pathlib import Path


def run_git(args: list[str]) -> subprocess.CompletedProcess:
    """执行 git 命令
    
    Args:
        args: git 命令参数列表
        
    Returns:
        subprocess.CompletedProcess 对象
    """
    return subprocess.run(
        ["git"] + args,
        capture_output=True,
        text=True,
        check=False
    )


def get_root_dir() -> Path:
    """获取 git 仓库根目录
    
    Raises:
        RuntimeError: 不在 git 仓库中
    """
    result = run_git(["rev-parse", "--show-toplevel"])
    if result.returncode != 0:
        raise RuntimeError("不在 git 仓库中")
    return Path(result.stdout.strip())


def fetch_remote() -> bool:
    """从远端获取最新分支信息
    
    Returns:
        是否成功获取
    """
    result = run_git(["fetch", "--quiet"])
    if result.returncode != 0:
        print("警告: 无法获取远端信息，继续使用本地数据")
        return False
    return True


def get_all_remote_branches() -> list[str]:
    """获取所有远端分支列表
    
    Returns:
        远端分支列表
    """
    result = run_git(["branch", "-r"])
    if result.returncode != 0:
        return []
    
    return [line.strip() for line in result.stdout.strip().split("\n") if line.strip()]


def get_remote_branches(branch_name: str) -> list[str]:
    """获取远端匹配的分支列表
    
    Args:
        branch_name: 分支名称
        
    Returns:
        匹配的远端分支列表
    """
    result = run_git(["branch", "-r"])
    if result.returncode != 0:
        return []
    
    return [
        line.strip()
        for line in result.stdout.strip().split("\n")
        if line.strip() and line.strip().endswith(f"/{branch_name}")
    ]


def branch_exists_local(branch_name: str) -> bool:
    """检查本地分支是否存在
    
    Args:
        branch_name: 分支名称
        
    Returns:
        是否存在
    """
    result = run_git(["show-ref", "--verify", "--quiet", f"refs/heads/{branch_name}"])
    return result.returncode == 0


def worktree_exists(worktree_path: Path) -> bool:
    """检查工作区是否存在
    
    Args:
        worktree_path: 工作区路径
        
    Returns:
        是否存在
    """
    result = run_git(["worktree", "list"])
    if result.returncode != 0:
        return False
    return str(worktree_path) in result.stdout


def extract_branch_name(remote_branch: str) -> str:
    """从远端分支名提取分支名
    
    Args:
        remote_branch: 远端分支名（如 origin/feature-123）
        
    Returns:
        分支名（如 feature-123）
    """
    return remote_branch.split("/", 1)[1] if "/" in remote_branch else remote_branch


def validate_branch_creation(branch_name: str, worktree_path: Path) -> None:
    """验证是否可以创建分支和工作区
    
    Args:
        branch_name: 分支名称
        worktree_path: 工作区路径
        
    Raises:
        RuntimeError: 验证失败
    """
    if worktree_path.exists():
        raise RuntimeError(f"工作区已存在于 {worktree_path}")
    
    if worktree_exists(worktree_path):
        raise RuntimeError(f"工作区 '{branch_name}' 已存在")
    
    if branch_exists_local(branch_name):
        raise RuntimeError(f"本地分支 '{branch_name}' 已存在")


def select_from_list(items: list[str], prompt: str, allow_create: bool = False) -> str | None:
    """让用户从列表中选择
    
    Args:
        items: 选项列表
        prompt: 提示信息
        allow_create: 是否允许创建新分支
        
    Returns:
        用户选择的项，或 None 表示创建新分支
    """
    if not items:
        return None
    
    print(prompt)
    for i, item in enumerate(items, 1):
        print(f"     {i}\t{item}")
    
    if allow_create:
        print(f"     {len(items) + 1}\t创建新分支")
    
    print()
    
    max_choice = len(items) + 1 if allow_create else len(items)
    
    while True:
        try:
            selection = int(input(f"请选择 (1-{max_choice}): "))
            if 1 <= selection <= len(items):
                selected = items[selection - 1]
                print(f"已选择: {selected}")
                return selected
            if allow_create and selection == len(items) + 1:
                return None
            print(f"错误: 请输入 1-{max_choice} 之间的数字")
        except ValueError:
            print("错误: 请输入有效的数字")
        except KeyboardInterrupt:
            print("\n操作已取消")
            sys.exit(1)


def input_branch_name() -> str:
    """让用户输入分支名称
    
    Returns:
        分支名称
    """
    while True:
        try:
            name = input("请输入新分支名称: ").strip()
            if name:
                return name
            print("错误: 分支名称不能为空")
        except KeyboardInterrupt:
            print("\n操作已取消")
            sys.exit(1)


def create_worktree(branch_name: str, worktree_path: Path, base_branch: str | None = None) -> None:
    """创建工作区
    
    Args:
        branch_name: 新分支名称
        worktree_path: 工作区路径
        base_branch: 基础分支（可选）
        
    Raises:
        RuntimeError: 创建失败
    """
    args = ["worktree", "add", "-b", branch_name, str(worktree_path)]
    if base_branch:
        args.append(base_branch)
    
    result = run_git(args)
    if result.returncode != 0:
        raise RuntimeError(f"创建工作区失败: {result.stderr.strip()}")


def create_worktree_with_validation(
    branch_name: str,
    worktree_path: Path,
    base_branch: str | None = None
) -> None:
    """验证并创建工作区
    
    Args:
        branch_name: 新分支名称
        worktree_path: 工作区路径
        base_branch: 基础分支（可选）
    """
    validate_branch_creation(branch_name, worktree_path)
    create_worktree(branch_name, worktree_path, base_branch)
    print(f"工作区已创建于 {worktree_path}")


def handle_with_branch_name(branch_name: str, worktrees_dir: Path) -> None:
    """处理有分支名参数的情况
    
    Args:
        branch_name: 分支名称
        worktrees_dir: 工作区目录
    """
    worktree_path = worktrees_dir / branch_name
    
    try:
        validate_branch_creation(branch_name, worktree_path)
    except RuntimeError as e:
        print(f"错误: {e}")
        sys.exit(1)
    
    remote_branches = get_remote_branches(branch_name)
    
    try:
        if remote_branches:
            selected_branch = select_from_list(
                remote_branches,
                "找到远端分支:",
                allow_create=True
            )
            if selected_branch:
                create_worktree(branch_name, worktree_path, selected_branch)
            else:
                create_worktree(branch_name, worktree_path)
        else:
            print("未找到远端分支，创建新分支")
            create_worktree(branch_name, worktree_path)
        
        print(f"工作区已创建于 {worktree_path}")
    except RuntimeError as e:
        print(f"错误: {e}")
        sys.exit(1)


def handle_without_branch_name(worktrees_dir: Path) -> None:
    """处理无分支名参数的情况
    
    Args:
        worktrees_dir: 工作区目录
    """
    remote_branches = get_all_remote_branches()
    
    if not remote_branches:
        print("未找到远端分支")
        sys.exit(1)
    
    selected_branch = select_from_list(
        remote_branches,
        "远端分支列表:",
        allow_create=True
    )
    
    if selected_branch:
        branch_name = extract_branch_name(selected_branch)
        worktree_path = worktrees_dir / branch_name
        
        try:
            create_worktree_with_validation(branch_name, worktree_path, selected_branch)
        except RuntimeError as e:
            print(f"错误: {e}")
            sys.exit(1)
    else:
        branch_name = input_branch_name()
        worktree_path = worktrees_dir / branch_name
        
        try:
            create_worktree_with_validation(branch_name, worktree_path)
        except RuntimeError as e:
            print(f"错误: {e}")
            sys.exit(1)


def main() -> None:
    parser = argparse.ArgumentParser(
        description="创建开发分支工作区",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
示例:
  %(prog)s                  # 列出远端分支供选择
  %(prog)s feature-123      # 创建 feature-123 工作区
  %(prog)s bugfix-456       # 创建 bugfix-456 工作区
        """
    )
    parser.add_argument("branch_name", nargs="?", help="分支名称（可选）")
    
    args = parser.parse_args()
    
    try:
        root_dir = get_root_dir()
    except RuntimeError as e:
        print(f"错误: {e}")
        sys.exit(1)
    
    worktrees_dir = root_dir / ".worktrees"
    worktrees_dir.mkdir(parents=True, exist_ok=True)
    
    print("正在从远端获取最新分支信息...")
    fetch_remote()
    
    if args.branch_name:
        handle_with_branch_name(args.branch_name, worktrees_dir)
    else:
        handle_without_branch_name(worktrees_dir)


if __name__ == "__main__":
    main()
