#!/usr/bin/env python3
"""Helper script for the #commit xprompt workflow.

Amends an existing CL after agent file changes, adding a HISTORY entry.
"""

import argparse
import json
import os
import subprocess
import sys
import tempfile


def _get_project_from_workspace() -> str | None:
    """Get the project name from the current workspace."""
    from sase.vcs_provider import get_vcs_provider

    provider = get_vcs_provider(os.getcwd())
    ok, name = provider.get_workspace_name(os.getcwd())
    if not ok or not name:
        return None
    return name


def _get_cl_name_from_branch() -> str | None:
    """Get the CL name from the current branch."""
    from sase.vcs_provider import get_vcs_provider

    provider = get_vcs_provider(os.getcwd())
    ok, name = provider.get_branch_name(os.getcwd())
    if not ok or not name:
        return None
    return name


def _build_note(
    who: str,
    note: str,
    response: str,
) -> str:
    """Build commit note with [who] prefix, auto-generating if needed."""
    from sase.summarize_utils import get_file_summary

    if note:
        return f"[{who}] {note}"

    # Auto-generate summary from response
    fd, response_tmp = tempfile.mkstemp(suffix=".md", prefix="sase_amend_response_")
    try:
        with os.fdopen(fd, "w", encoding="utf-8") as f:
            f.write(response)
        summary = get_file_summary(
            response_tmp,
            usage="a concise description of the changes made",
            fallback="Agent changes",
        )
    finally:
        try:
            os.unlink(response_tmp)
        except OSError:
            pass
    return f"[{who}] {summary}"


def _amend_cl(
    who: str,
    note: str,
    data_file: str,
) -> tuple[bool, str, str, str, str]:
    """Amend the current CL with a HISTORY entry.

    Args:
        who: Identifier for who is amending (e.g., "man", "mentor:name").
        note: The note for the HISTORY entry (empty string to auto-generate).
        data_file: Path to JSON file containing prompt and response from agent.

    Returns:
        Tuple of (success, entry_id, cl_name, error_message, diff_path)
    """
    from sase.vcs_provider import detect_vcs_family

    vcs_type = detect_vcs_family(os.getcwd())

    if vcs_type == "git":
        return _amend_cl_git(who, note, data_file)
    else:
        return _amend_cl_hg(who, note, data_file)


def _amend_cl_git(
    who: str,
    note: str,
    data_file: str,
) -> tuple[bool, str, str, str, str]:
    """Git-specific commit workflow.

    On master/main: commit directly and auto-push.
    On PR branch: commit, push, and add HISTORY entry to ChangeSpec.
    """
    from sase.chat_history import save_chat_history
    from sase.commit_utils.workspace import save_diff
    from sase.sase_utils import generate_timestamp

    # Detect branch
    branch = _get_cl_name_from_branch()
    is_default_branch = branch in ("master", "main", None)

    # Load prompt and response from data file
    with open(data_file, "r", encoding="utf-8") as f:
        data = json.load(f)
    prompt = data["prompt"]
    response = data["response"]

    # Get project name
    project = _get_project_from_workspace()
    if not project:
        return False, "", "", "Could not determine project from workspace", ""

    # Generate timestamp
    timestamp = generate_timestamp()

    # Save diff for audit trail (save_diff internally calls git add -A)
    diff_label = f"master_{project}" if is_default_branch else (branch or project)
    diff_path = save_diff(diff_label, target_dir=None, timestamp=timestamp)
    if not diff_path:
        return False, "", "", "No changes to commit (diff is empty)", ""

    # Build note
    commit_note = _build_note(who, note, response)

    # Save chat history
    save_chat_history(
        prompt=prompt,
        response=response,
        workflow="amend",
        timestamp=timestamp,
    )

    # Commit
    result = subprocess.run(
        ["git", "commit", "-m", commit_note],
        capture_output=True,
        text=True,
        check=False,
    )
    if result.returncode != 0:
        return False, "", "", f"git commit failed: {result.stderr}", ""

    # Auto-push with rebase-retry
    for _attempt in range(3):
        push_result = subprocess.run(
            ["git", "push", "origin", "HEAD"],
            capture_output=True,
            text=True,
            check=False,
        )
        if push_result.returncode == 0:
            break
        # Pull with rebase and retry
        subprocess.run(
            ["git", "pull", "--rebase", "--quiet"],
            capture_output=True,
            text=True,
            check=False,
        )

    if is_default_branch:
        # Get short SHA
        sha_result = subprocess.run(
            ["git", "rev-parse", "--short", "HEAD"],
            capture_output=True,
            text=True,
            check=False,
        )
        short_sha = sha_result.stdout.strip() if sha_result.returncode == 0 else ""
        return True, short_sha, "", "", diff_path or ""
    else:
        # PR branch path: add HISTORY entry to ChangeSpec
        from sase.commit_utils.entries import add_commit_entry, get_next_commit_number
        from sase.workflow_utils import (
            add_test_hooks_if_available,
            get_project_file_path,
        )

        project_file = get_project_file_path(project)
        if not os.path.exists(project_file):
            return False, "", "", f"Project file not found: {project_file}", ""

        # Convert branch name to ChangeSpec name: {project}_{branch_with_underscores}
        cl_name = f"{project}_{branch.replace('-', '_')}" if branch else ""

        # Add HISTORY entry (non-fatal: ChangeSpec may not exist yet if
        # created in #pr post-steps after the agent finishes)
        success = add_commit_entry(
            project_file=project_file,
            cl_name=cl_name,
            note=commit_note,
            diff_path=diff_path,
            chat_path="",
            end_timestamp=timestamp,
        )

        if not success:
            # ChangeSpec doesn't exist yet — commit+push already happened,
            # which is what matters. create_changespec_for_workflow() will
            # capture all commits when it runs later.
            sha_result = subprocess.run(
                ["git", "rev-parse", "--short", "HEAD"],
                capture_output=True,
                text=True,
                check=False,
            )
            short_sha = sha_result.stdout.strip() if sha_result.returncode == 0 else ""
            return True, short_sha, "", "", diff_path or ""

        # Add test hooks if available
        add_test_hooks_if_available(project_file, cl_name)

        # Get entry ID
        with open(project_file, encoding="utf-8") as f:
            lines = f.readlines()
        entry_id = str(get_next_commit_number(lines, cl_name) - 1)

        return True, entry_id, cl_name, "", diff_path or ""


def _amend_cl_hg(
    who: str,
    note: str,
    data_file: str,
) -> tuple[bool, str, str, str, str]:
    """Hg-specific commit workflow (original _amend_cl logic)."""
    from sase.chat_history import save_chat_history
    from sase.commit_utils.entries import add_commit_entry
    from sase.commit_utils.workspace import save_diff
    from sase.sase_utils import generate_timestamp
    from sase.workflow_utils import add_test_hooks_if_available, get_project_file_path

    # Load prompt and response from data file
    with open(data_file, "r", encoding="utf-8") as f:
        data = json.load(f)
    prompt = data["prompt"]
    response = data["response"]

    # Get CL name from branch
    cl_name = _get_cl_name_from_branch()
    if not cl_name:
        return False, "", "", "Could not determine CL name from branch", ""

    # Get project name
    project = _get_project_from_workspace()
    if not project:
        return False, "", "", "Could not determine project from workspace", ""

    # Get project file path
    project_file = get_project_file_path(project)
    if not os.path.exists(project_file):
        return False, "", "", f"Project file not found: {project_file}", ""

    # Generate timestamp for consistent filenames
    timestamp = generate_timestamp()

    # Save the current diff before amending
    diff_path = save_diff(cl_name, target_dir=None, timestamp=timestamp)
    if not diff_path:
        return False, "", "", "No changes to amend (diff is empty)", ""

    # Build note with [who] prefix
    commit_note = _build_note(who, note, response)

    # Save chat history with actual prompt
    chat_path = save_chat_history(
        prompt=prompt,
        response=response,
        workflow="amend",
        timestamp=timestamp,
    )

    # Run bb_hg_amend
    try:
        result = subprocess.run(
            ["bb_hg_amend", commit_note],
            capture_output=True,
            text=True,
            check=False,
        )
        if result.returncode != 0:
            return False, "", "", f"bb_hg_amend failed: {result.stderr}", ""
    except FileNotFoundError:
        return False, "", "", "bb_hg_amend command not found", ""

    # Add HISTORY entry
    success = add_commit_entry(
        project_file=project_file,
        cl_name=cl_name,
        note=commit_note,
        diff_path=diff_path,
        chat_path=chat_path,
        end_timestamp=timestamp,
    )

    if not success:
        return False, "", "", f"Failed to add HISTORY entry for {cl_name}", ""

    # Add test hooks if available
    add_test_hooks_if_available(project_file, cl_name)

    # Get the entry ID (next commit number - 1 since we just added it)
    from sase.commit_utils.entries import get_next_commit_number

    with open(project_file, encoding="utf-8") as f:
        lines = f.readlines()
    entry_id = str(get_next_commit_number(lines, cl_name) - 1)

    return True, entry_id, cl_name, "", diff_path or ""


def main() -> None:
    """Main entry point."""
    parser = argparse.ArgumentParser(
        description="Helper for the #commit xprompt workflow (amend)"
    )
    parser.add_argument(
        "--who", default="man", help="Identifier for who is amending the CL"
    )
    parser.add_argument(
        "--note", default="", help="Note for the HISTORY entry (auto-generated if empty)"
    )
    parser.add_argument(
        "--data-file", required=True, help="Path to JSON file with prompt and response"
    )

    args = parser.parse_args()

    # Redirect stdout to stderr during CL amend to prevent
    # stray prints from corrupting the JSON output parsed by
    # the parent process (parse_bash_output).
    saved_stdout = sys.stdout
    sys.stdout = sys.stderr
    try:
        success, entry_id, cl_name, error, diff_path = _amend_cl(
            args.who, args.note, args.data_file
        )
    finally:
        sys.stdout = saved_stdout
    print(json.dumps({
        "success": success,
        "entry_id": entry_id,
        "cl_name": cl_name,
        "diff_path": diff_path,
        "error": error,
    }))


if __name__ == "__main__":
    main()
