"""Tests for ievo init command."""

from __future__ import annotations

from pathlib import Path
from unittest.mock import patch

import pytest
import typer

from ievo.commands.init import _write_if_missing, init


@pytest.fixture(autouse=True)
def _mock_global_init(tmp_path: Path):
    """Mock ensure_home and github auth for all init tests."""
    fake_home = tmp_path / ".fake-ievo"
    fake_home.mkdir()
    with (
        patch("ievo.commands.init.ensure_home", return_value=fake_home),
        patch("ievo.core.global_config.get_config", return_value="gh_cli"),
    ):
        yield


def test_init_creates_project(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    project_dir = tmp_path / "my-project"

    init(name="my-project")

    assert (project_dir / "ievo.yaml").exists()
    assert (project_dir / "CLAUDE.md").exists()
    assert (project_dir / "PRIORITY.md").exists()
    assert (project_dir / ".gitignore").exists()
    assert (project_dir / "spec" / "SPEC_INDEX.md").exists()
    assert (project_dir / "spec" / "requirements").is_dir()
    assert (project_dir / "spec" / "changes").is_dir()
    assert (project_dir / "spec" / "questions").is_dir()
    assert (project_dir / "spec" / "templates").is_dir()
    assert (project_dir / "plans").is_dir()
    assert (project_dir / "agents").is_dir()


def test_init_current_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name=".")

    assert (tmp_path / "ievo.yaml").exists()
    assert (tmp_path / "PRIORITY.md").exists()


def test_init_rejects_duplicate(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    (tmp_path / "ievo.yaml").write_text("project: existing")

    with pytest.raises(typer.Exit):
        init(name=".")


def test_init_creates_github_workflows(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="wf-test")

    project_dir = tmp_path / "wf-test"
    assert (project_dir / ".github" / "workflows" / "spec-writer.yml").exists()
    assert (project_dir / ".github" / "workflows" / "architect-agent.yml").exists()
    assert (project_dir / ".github" / "workflows" / "coder-agent.yml").exists()


def test_init_creates_issue_templates(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="tpl-test")

    project_dir = tmp_path / "tpl-test"
    assert (project_dir / ".github" / "ISSUE_TEMPLATE" / "feature.md").exists()
    assert (project_dir / ".github" / "ISSUE_TEMPLATE" / "change.md").exists()


def test_init_priority_contains_formula(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="formula-test")

    content = (tmp_path / "formula-test" / "PRIORITY.md").read_text()
    assert "priority_weight" in content
    assert "dependency_satisfaction" in content
    assert "score =" in content


def test_init_spec_index_contains_legend(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="legend-test")

    content = (tmp_path / "legend-test" / "spec" / "SPEC_INDEX.md").read_text()
    assert "Status Legend" in content
    assert "ready" in content
    assert "implemented" in content


# ── New tests ──────────────────────────────────────────────────


def test_init_creates_gitkeep_in_empty_dirs(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="gk-test")

    project_dir = tmp_path / "gk-test"
    for d in ["spec/requirements", "spec/changes", "spec/questions", "plans", "agents"]:
        assert (project_dir / d / ".gitkeep").exists(), f"Missing .gitkeep in {d}"


def test_init_creates_gitignore(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="gi-test")

    content = (tmp_path / "gi-test" / ".gitignore").read_text()
    assert ".env" in content
    assert "__pycache__" in content


def test_init_creates_architect_workflow(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="arch-test")

    content = (tmp_path / "arch-test" / ".github" / "workflows" / "architect-agent.yml").read_text()
    assert "Architect Agent" in content
    assert "ANTHROPIC_API_KEY" in content


def test_init_claude_md_has_scaffold(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="claude-test")

    content = (tmp_path / "claude-test" / "CLAUDE.md").read_text()
    assert "# claude-test" in content
    assert "Tech stack" in content
    assert "Conventions" in content
    assert "What this project is" in content


def test_init_creates_spec_templates(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="tpl2-test")

    project_dir = tmp_path / "tpl2-test"
    assert (project_dir / "spec" / "templates" / "REQ_TEMPLATE.md").exists()
    assert (project_dir / "spec" / "templates" / "CR_TEMPLATE.md").exists()

    req_content = (project_dir / "spec" / "templates" / "REQ_TEMPLATE.md").read_text()
    assert "Acceptance Criteria" in req_content

    cr_content = (project_dir / "spec" / "templates" / "CR_TEMPLATE.md").read_text()
    assert "What Changes" in cr_content


# ── Claude Code hooks tests ───────────────────────────────────


def test_init_creates_claude_hooks_dir(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="hooks-test")

    assert (tmp_path / "hooks-test" / ".claude" / "hooks").is_dir()


def test_init_creates_precompact_hook(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="hook-script-test")

    hook_file = tmp_path / "hook-script-test" / ".claude" / "hooks" / "precompact_save.py"
    assert hook_file.exists()
    content = hook_file.read_text()
    assert "PreCompact" in content
    assert "claude-mem" in content
    assert "def main()" in content


def test_init_creates_settings_local(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    import json

    monkeypatch.chdir(tmp_path)
    init(name="settings-test")

    settings_file = tmp_path / "settings-test" / ".claude" / "settings.local.json"
    assert settings_file.exists()
    data = json.loads(settings_file.read_text())
    assert "hooks" in data
    assert "PreCompact" in data["hooks"]


def test_init_gitignore_includes_settings_local(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
    monkeypatch.chdir(tmp_path)
    init(name="gi-local-test")

    content = (tmp_path / "gi-local-test" / ".gitignore").read_text()
    assert "settings.local.json" in content


# ── _write_if_missing ────────────────────────────────────────


def test_write_if_missing_creates_file(tmp_path: Path) -> None:
    """Creates file when it doesn't exist."""
    target = tmp_path / "new_file.txt"
    assert _write_if_missing(target, "content") is True
    assert target.read_text() == "content"


def test_write_if_missing_skips_existing(tmp_path: Path) -> None:
    """Returns False when file already exists."""
    target = tmp_path / "existing.txt"
    target.write_text("original")
    assert _write_if_missing(target, "new content") is False
    assert target.read_text() == "original"


# ── Init with pre-existing files ─────────────────────────────


def test_init_skips_existing_files(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """Init skips files that already exist (branch coverage)."""
    monkeypatch.chdir(tmp_path)
    project_dir = tmp_path / "preexist-test"
    project_dir.mkdir()

    # Pre-create some files that init would normally create
    (project_dir / "CLAUDE.md").write_text("# Existing CLAUDE.md")
    (project_dir / "PRIORITY.md").write_text("# Existing PRIORITY.md")
    (project_dir / ".gitignore").write_text("# Existing gitignore")
    (project_dir / "spec").mkdir(parents=True)
    (project_dir / "spec" / "SPEC_INDEX.md").write_text("# Existing spec index")
    (project_dir / "spec" / "templates").mkdir(parents=True)
    (project_dir / "spec" / "templates" / "REQ_TEMPLATE.md").write_text("# Existing")
    (project_dir / "spec" / "templates" / "CR_TEMPLATE.md").write_text("# Existing")
    (project_dir / ".github" / "workflows").mkdir(parents=True)
    (project_dir / ".github" / "workflows" / "spec-writer.yml").write_text("# Existing")
    (project_dir / ".github" / "workflows" / "architect-agent.yml").write_text("# Existing")
    (project_dir / ".github" / "workflows" / "coder-agent.yml").write_text("# Existing")
    (project_dir / ".github" / "ISSUE_TEMPLATE").mkdir(parents=True)
    (project_dir / ".github" / "ISSUE_TEMPLATE" / "feature.md").write_text("# Existing")
    (project_dir / ".github" / "ISSUE_TEMPLATE" / "change.md").write_text("# Existing")
    (project_dir / ".claude" / "hooks").mkdir(parents=True)
    (project_dir / ".claude" / "hooks" / "precompact_save.py").write_text("# Existing")
    (project_dir / ".claude" / "settings.local.json").write_text("{}")

    # Pre-create .gitkeep files in empty dirs so init skips writing them
    for d in ["spec/requirements", "spec/changes", "spec/questions", "plans", "agents"]:
        (project_dir / d).mkdir(parents=True, exist_ok=True)
        (project_dir / d / ".gitkeep").write_text("")

    init(name="preexist-test")

    # Files should NOT be overwritten
    assert (project_dir / "CLAUDE.md").read_text() == "# Existing CLAUDE.md"
    assert (project_dir / "PRIORITY.md").read_text() == "# Existing PRIORITY.md"


# ── Init with github auth prompt ─────────────────────────────


def test_init_prompts_github_auth(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
    """First init prompts for github auth when config is None."""
    monkeypatch.chdir(tmp_path)
    fake_home = tmp_path / ".fake-ievo"
    fake_home.mkdir(exist_ok=True)

    with (
        patch("ievo.commands.init.ensure_home", return_value=fake_home),
        patch("ievo.core.global_config.get_config", return_value=None),
        patch("ievo.core.github_auth.prompt_github_auth") as mock_auth,
    ):
        init(name="auth-test")

    mock_auth.assert_called_once_with(fake_home)
