"""Integration-style tests that exercise the CLI entry point."""

from __future__ import annotations

import os
import subprocess
import sys
from pathlib import Path

import pytest

REPO_ROOT = Path(__file__).resolve().parents[1]


def _invoke_cli(
    *args: str,
    cwd: Path | None = None,
    env: dict[str, str] | None = None,
) -> subprocess.CompletedProcess[str]:
    """Run the CLI module with the provided arguments and environment."""
    full_env = os.environ.copy()
    if env:
        full_env.update(env)
    command = [
        sys.executable,
        "-m",
        "stilyagi.stilyagi",
        "zip",
        *args,
    ]
    return subprocess.run(  # noqa: S603 - arguments are repository-controlled
        command,
        cwd=str(cwd or REPO_ROOT),
        text=True,
        capture_output=True,
    )


@pytest.fixture
def staged_project(tmp_path: Path) -> Path:
    """Create a minimal style tree in a temporary staging directory."""
    project_root = tmp_path / "staging"
    rule = project_root / "styles" / "concordat" / "Rule.yml"
    rule.parent.mkdir(parents=True, exist_ok=True)
    rule.write_text("extends: existence\n", encoding="utf-8")

    vocab = project_root / "styles" / "config" / "vocabularies" / "concordat"
    vocab.mkdir(parents=True, exist_ok=True)
    (vocab / "accept.txt").write_text("allowlist\n", encoding="utf-8")
    return project_root


def test_cli_errors_when_styles_directory_missing(tmp_path: Path) -> None:
    """Fail with a helpful message when the styles directory is absent."""
    result = _invoke_cli("--project-root", str(tmp_path))
    assert result.returncode != 0, (
        f"Expected non-zero exit when styles directory is missing: {result.stderr}"
    )
    assert "does not exist" in result.stderr, (
        "Missing-styles error message should mention 'does not exist'"
    )


def test_cli_refuses_to_overwrite_without_force(staged_project: Path) -> None:
    """Refuse to overwrite archives when --force is not provided."""
    base_args = [
        "--project-root",
        str(staged_project),
        "--archive-version",
        "7.7.7",
    ]
    first = _invoke_cli(*base_args)
    assert first.returncode == 0, (
        f"Initial packaging should succeed: {first.stderr or first.stdout}"
    )

    second = _invoke_cli(*base_args)
    assert second.returncode != 0, (
        "Second packaging should fail without --force: "
        f"{second.stderr or second.stdout}"
    )
    assert "already exists" in second.stderr, (
        f"Expected overwrite warning in stderr: {second.stderr}"
    )


def test_cli_emits_single_archive_path_line(staged_project: Path) -> None:
    """Emit one newline-terminated archive path on stdout."""
    version = "9.9.9"
    result = _invoke_cli(
        "--project-root",
        str(staged_project),
        "--archive-version",
        version,
        "--force",
    )
    assert result.returncode == 0, (
        f"Packaging should succeed: {result.stderr or result.stdout}"
    )
    non_empty_lines = [line for line in result.stdout.splitlines() if line.strip()]
    expected_path = staged_project / "dist" / f"concordat-{version}.zip"
    assert non_empty_lines == [str(expected_path)], (
        "stdout should contain exactly one archive path line"
    )
