"""Black-box integration tests for the installed metabranch CLI."""

from __future__ import annotations

from pathlib import Path

import textwrap
import yaml

from tests.helpers import git, run


def run_cli(
    installed_cli_env: dict[str, Path],
    cwd: Path,
    *args: str,
    env: dict[str, str] | None = None,
):
    """Run the installed metabranch CLI in a separate repo."""
    return run(cwd, str(installed_cli_env["cli"]), *args, env=env)


def test_installed_cli_help(installed_cli_env: dict[str, Path], repo_with_branches: Path) -> None:
    result = run_cli(installed_cli_env, repo_with_branches, "--help")

    assert result.returncode == 0
    assert "Metabranch - A tool for managing git metabranches." in result.stdout
    assert "commit" in result.stdout
    assert "pull" in result.stdout
    assert result.stderr == ""


def test_installed_cli_can_create_and_list_metabranch(
    installed_cli_env: dict[str, Path], repo_with_branches: Path
) -> None:
    result = run_cli(
        installed_cli_env,
        repo_with_branches,
        "checkout",
        "-b",
        "meta",
        "feature-one",
        "feature-two",
    )
    assert result.returncode == 0
    assert git(repo_with_branches, "branch", "--show-current") == "meta"

    config_path = repo_with_branches / ".metabranch.yaml"
    assert config_path.exists() is True
    config = yaml.safe_load(config_path.read_text())
    assert config["metabranch"]["name"] == "meta"
    assert config["metabranch"]["base_ref"] == "master"
    assert config["metabranch"]["branches"] == ["feature-one", "feature-two"]

    branch_result = run_cli(installed_cli_env, repo_with_branches, "branch")
    assert branch_result.returncode == 0
    assert "meta" in branch_result.stdout
    assert "Contained Branches" in branch_result.stdout

    status_result = run_cli(installed_cli_env, repo_with_branches, "status")
    assert status_result.returncode == 0
    assert "Metabranch Status" in status_result.stdout
    assert "feature-one" in status_result.stdout
    assert "feature-two" in status_result.stdout


def test_installed_cli_branch_creates_without_checkout(
    installed_cli_env: dict[str, Path], repo_with_branches: Path
) -> None:
    result = run_cli(
        installed_cli_env,
        repo_with_branches,
        "branch",
        "meta",
        "feature-one",
        "feature-one",
    )
    assert result.returncode == 0
    assert "duplicate branches in branch request were ignored" in result.stdout
    assert git(repo_with_branches, "branch", "--show-current") == "master"

    checkout = run_cli(installed_cli_env, repo_with_branches, "checkout", "meta")
    assert checkout.returncode == 0
    assert git(repo_with_branches, "branch", "--show-current") == "meta"
    assert (repo_with_branches / "feature_one.txt").read_text() == "one\n"


def test_installed_cli_rebase_reports_progress(
    installed_cli_env: dict[str, Path], repo_with_branches: Path
) -> None:
    create = run_cli(
        installed_cli_env,
        repo_with_branches,
        "checkout",
        "-b",
        "meta",
        "feature-one",
        "feature-two",
    )
    assert create.returncode == 0

    rebase = run_cli(installed_cli_env, repo_with_branches, "rebase")
    assert rebase.returncode == 0
    assert "Rebasing metabranch meta onto master" in rebase.stdout
    assert "Rebuilding metabranch contents" in rebase.stdout
    assert "Updating metabranch metadata" in rebase.stdout


def test_installed_cli_rejects_plain_branch_checkout(
    installed_cli_env: dict[str, Path], repo_with_branches: Path
) -> None:
    create = run_cli(
        installed_cli_env,
        repo_with_branches,
        "checkout",
        "-b",
        "meta",
        "feature-one",
    )
    assert create.returncode == 0

    plain = run_cli(installed_cli_env, repo_with_branches, "checkout", "feature-one")
    assert plain.returncode != 0
    assert "regular Git branch" in plain.stderr
    assert git(repo_with_branches, "branch", "--show-current") == "meta"

    meta = run_cli(installed_cli_env, repo_with_branches, "checkout", "meta")
    assert meta.returncode == 0
    assert "regular Git branch" not in meta.stdout
    assert git(repo_with_branches, "branch", "--show-current") == "meta"


def test_installed_cli_reconciles_direct_commits_via_editor(
    installed_cli_env: dict[str, Path], repo_with_branches: Path, tmp_path: Path
) -> None:
    create = run_cli(
        installed_cli_env,
        repo_with_branches,
        "checkout",
        "-b",
        "meta",
        "feature-one",
    )
    assert create.returncode == 0
    assert run_cli(installed_cli_env, repo_with_branches, "rebase").returncode == 0

    (repo_with_branches / "feature_one.txt").write_text("integration\n")
    git(repo_with_branches, "add", "feature_one.txt")
    git(repo_with_branches, "commit", "-m", "Direct reconcile")

    editor_script = tmp_path / "editor.sh"
    editor_script.write_text(
        textwrap.dedent(
            """\
            #!/bin/sh
            perl -0pi -e 's/^\\? /feature-one /m' "$1"
            """
        )
    )
    editor_script.chmod(0o755)
    git(repo_with_branches, "config", "--local", "core.editor", str(editor_script))

    result = run_cli(
        installed_cli_env,
        repo_with_branches,
        "rebase",
    )
    assert result.returncode == 0
    assert git(repo_with_branches, "log", "-1", "--format=%s", "feature-one") == "Direct reconcile"


def test_installed_cli_commit_reconciles_immediately(
    installed_cli_env: dict[str, Path], repo_with_branches: Path, tmp_path: Path
) -> None:
    create = run_cli(
        installed_cli_env,
        repo_with_branches,
        "checkout",
        "-b",
        "meta",
        "feature-one",
    )
    assert create.returncode == 0

    editor_script = tmp_path / "editor.sh"
    editor_script.write_text(
        textwrap.dedent(
            """\
            #!/bin/sh
            perl -0pi -e 's/^\\? /feature-one /m' "$1"
            """
        )
    )
    editor_script.chmod(0o755)
    git(repo_with_branches, "config", "--local", "core.editor", str(editor_script))

    (repo_with_branches / "feature_one.txt").write_text("via-commit\n")
    git(repo_with_branches, "add", "feature_one.txt")

    result = run_cli(
        installed_cli_env,
        repo_with_branches,
        "commit",
        "-m",
        "Commit and reconcile",
    )
    assert result.returncode == 0
    assert "Committing changes on metabranch meta" in result.stdout
    assert "Reconciling metabranch-only commits" in result.stdout
    assert git(repo_with_branches, "log", "-1", "--format=%s", "feature-one") == (
        "Commit and reconcile"
    )
