#!/usr/bin/env python3
"""
Multi-Agent Pipeline: Create PR.

Usage:
    python3 create_pr.py [task-dir] [--dry-run]

This script:
1. Stages and commits all changes (excluding workspace/)
2. Pushes to origin
3. Creates a Draft PR using `gh pr create`
4. Updates task.json with status="completed", pr_url, and current_phase

Note: This is the only action that performs git commit, as it's the final
step after all implementation and checks are complete.
"""

from __future__ import annotations

import argparse
import json
import subprocess
import sys
from pathlib import Path

# Add parent directory to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))

from common.git_context import _run_git_command
from common.paths import (
    DIR_WORKFLOW,
    FILE_TASK_JSON,
    get_current_task,
    get_repo_root,
)
from common.phase import get_phase_for_action

# =============================================================================
# Colors
# =============================================================================


class Colors:
    RED = "\033[0;31m"
    GREEN = "\033[0;32m"
    YELLOW = "\033[1;33m"
    BLUE = "\033[0;34m"
    NC = "\033[0m"


# =============================================================================
# Helper Functions
# =============================================================================


def _read_json_file(path: Path) -> dict | None:
    """Read and parse a JSON file."""
    try:
        return json.loads(path.read_text(encoding="utf-8"))
    except (FileNotFoundError, json.JSONDecodeError, OSError):
        return None


def _write_json_file(path: Path, data: dict) -> bool:
    """Write dict to JSON file."""
    try:
        path.write_text(
            json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8"
        )
        return True
    except (OSError, IOError):
        return False


# =============================================================================
# Main
# =============================================================================


def main() -> int:
    """Main entry point."""
    parser = argparse.ArgumentParser(description="Multi-Agent Pipeline: Create PR")
    parser.add_argument("dir", nargs="?", help="Task directory")
    parser.add_argument(
        "--dry-run", action="store_true", help="Show what would be done"
    )

    args = parser.parse_args()
    repo_root = get_repo_root()

    # =============================================================================
    # Get Task Directory
    # =============================================================================
    target_dir = args.dir
    if not target_dir:
        # Try to get from .current-task
        current_task = get_current_task(repo_root)
        if current_task:
            target_dir = current_task

    if not target_dir:
        print(
            f"{Colors.RED}Error: No task directory specified and no current task set{Colors.NC}"
        )
        print("Usage: python3 create_pr.py [task-dir] [--dry-run]")
        return 1

    # Support relative paths
    if not target_dir.startswith("/"):
        target_dir_path = repo_root / target_dir
    else:
        target_dir_path = Path(target_dir)

    task_json = target_dir_path / FILE_TASK_JSON
    if not task_json.is_file():
        print(f"{Colors.RED}Error: task.json not found at {target_dir_path}{Colors.NC}")
        return 1

    # =============================================================================
    # Main
    # =============================================================================
    print(f"{Colors.BLUE}=== Create PR ==={Colors.NC}")
    if args.dry_run:
        print(
            f"{Colors.YELLOW}[DRY-RUN MODE] No actual changes will be made{Colors.NC}"
        )
    print()

    # Read task config
    task_data = _read_json_file(task_json)
    if not task_data:
        print(f"{Colors.RED}Error: Failed to read task.json{Colors.NC}")
        return 1

    task_name = task_data.get("name", "")
    base_branch = task_data.get("base_branch", "main")
    scope = task_data.get("scope", "core")
    dev_type = task_data.get("dev_type", "feature")

    # Map dev_type to commit prefix
    prefix_map = {
        "feature": "feat",
        "frontend": "feat",
        "backend": "feat",
        "fullstack": "feat",
        "bugfix": "fix",
        "fix": "fix",
        "refactor": "refactor",
        "docs": "docs",
        "test": "test",
    }
    commit_prefix = prefix_map.get(dev_type, "feat")

    print(f"Task: {task_name}")
    print(f"Base branch: {base_branch}")
    print(f"Scope: {scope}")
    print(f"Commit prefix: {commit_prefix}")
    print()

    # Get current branch
    _, branch_out, _ = _run_git_command(["branch", "--show-current"])
    current_branch = branch_out.strip()
    print(f"Current branch: {current_branch}")

    # Check for changes
    print(f"{Colors.YELLOW}Checking for changes...{Colors.NC}")

    # Stage changes
    _run_git_command(["add", "-A"])

    # Exclude workspace and temp files
    _run_git_command(["reset", f"{DIR_WORKFLOW}/workspace/"])
    _run_git_command(["reset", ".agent-log", ".session-id"])

    # Check if there are staged changes
    ret, _, _ = _run_git_command(["diff", "--cached", "--quiet"])
    has_staged_changes = ret != 0

    if not has_staged_changes:
        print(f"{Colors.YELLOW}No staged changes to commit{Colors.NC}")

        # Check for unpushed commits
        ret, log_out, _ = _run_git_command(
            ["log", f"origin/{current_branch}..HEAD", "--oneline"]
        )
        unpushed = len([line for line in log_out.splitlines() if line.strip()])

        if unpushed == 0:
            if args.dry_run:
                _run_git_command(["reset", "HEAD"])
            print(f"{Colors.RED}No changes to create PR{Colors.NC}")
            return 1

        print(f"Found {unpushed} unpushed commit(s)")
    else:
        # Commit changes
        print(f"{Colors.YELLOW}Committing changes...{Colors.NC}")
        commit_msg = f"{commit_prefix}({scope}): {task_name}"

        if args.dry_run:
            print(f"[DRY-RUN] Would commit with message: {commit_msg}")
            print("[DRY-RUN] Staged files:")
            _, staged_out, _ = _run_git_command(["diff", "--cached", "--name-only"])
            for line in staged_out.splitlines():
                print(f"  - {line}")
        else:
            _run_git_command(["commit", "-m", commit_msg])
            print(f"{Colors.GREEN}Committed: {commit_msg}{Colors.NC}")

    # Push to remote
    print(f"{Colors.YELLOW}Pushing to remote...{Colors.NC}")
    if args.dry_run:
        print(f"[DRY-RUN] Would push to: origin/{current_branch}")
    else:
        ret, _, err = _run_git_command(["push", "-u", "origin", current_branch])
        if ret != 0:
            print(f"{Colors.RED}Failed to push: {err}{Colors.NC}")
            return 1
        print(f"{Colors.GREEN}Pushed to origin/{current_branch}{Colors.NC}")

    # Create PR
    print(f"{Colors.YELLOW}Creating PR...{Colors.NC}")
    pr_title = f"{commit_prefix}({scope}): {task_name}"
    pr_url = ""

    if args.dry_run:
        print("[DRY-RUN] Would create PR:")
        print(f"  Title: {pr_title}")
        print(f"  Base:  {base_branch}")
        print(f"  Head:  {current_branch}")
        prd_file = target_dir_path / "prd.md"
        if prd_file.is_file():
            print("  Body:  (from prd.md)")
        pr_url = "https://github.com/example/repo/pull/DRY-RUN"
    else:
        # Check if PR already exists
        result = subprocess.run(
            [
                "gh",
                "pr",
                "list",
                "--head",
                current_branch,
                "--base",
                base_branch,
                "--json",
                "url",
                "--jq",
                ".[0].url",
            ],
            capture_output=True,
            text=True,
            encoding="utf-8",
            errors="replace",
        )
        existing_pr = result.stdout.strip()

        if existing_pr:
            print(f"{Colors.YELLOW}PR already exists: {existing_pr}{Colors.NC}")
            pr_url = existing_pr
        else:
            # Read PRD as PR body
            pr_body = ""
            prd_file = target_dir_path / "prd.md"
            if prd_file.is_file():
                pr_body = prd_file.read_text(encoding="utf-8")

            # Create PR
            result = subprocess.run(
                [
                    "gh",
                    "pr",
                    "create",
                    "--draft",
                    "--base",
                    base_branch,
                    "--title",
                    pr_title,
                    "--body",
                    pr_body,
                ],
                capture_output=True,
                text=True,
                encoding="utf-8",
                errors="replace",
            )

            if result.returncode != 0:
                print(f"{Colors.RED}Failed to create PR: {result.stderr}{Colors.NC}")
                return 1

            pr_url = result.stdout.strip()
            print(f"{Colors.GREEN}PR created: {pr_url}{Colors.NC}")

    # Update task.json
    print(f"{Colors.YELLOW}Updating task status...{Colors.NC}")
    if args.dry_run:
        print("[DRY-RUN] Would update task.json:")
        print("  status: completed")
        print(f"  pr_url: {pr_url}")
        print("  current_phase: (set to create-pr phase)")
    else:
        # Get the phase number for create-pr action
        create_pr_phase = get_phase_for_action(task_json, "create-pr")
        if not create_pr_phase:
            create_pr_phase = 4  # Default fallback

        task_data["status"] = "completed"
        task_data["pr_url"] = pr_url
        task_data["current_phase"] = create_pr_phase

        _write_json_file(task_json, task_data)
        print(
            f"{Colors.GREEN}Task status updated to 'completed', phase {create_pr_phase}{Colors.NC}"
        )

    # In dry-run, reset the staging area
    if args.dry_run:
        _run_git_command(["reset", "HEAD"])

    print()
    print(f"{Colors.GREEN}=== PR Created Successfully ==={Colors.NC}")
    print(f"PR URL: {pr_url}")

    return 0


if __name__ == "__main__":
    sys.exit(main())
