"""Tests for init_templates, bundled marketplace templates, and ievo.core.templates."""

from __future__ import annotations

import json
from pathlib import Path
from unittest.mock import patch

import yaml

from ievo.commands.init_templates import (
    CLAUDE_MD,
    CLAUDE_SETTINGS_LOCAL_JSON,
    GITIGNORE,
    SPEC_INDEX_MD,
)
from ievo.marketplace import bundled_template_path


def test_spec_index_has_status_legend() -> None:
    assert "Status Legend" in SPEC_INDEX_MD
    assert "draft" in SPEC_INDEX_MD
    assert "ready" in SPEC_INDEX_MD
    assert "implemented" in SPEC_INDEX_MD
    assert "blocked" in SPEC_INDEX_MD


def test_spec_index_has_dependency_rules() -> None:
    assert "Dependency Rules" in SPEC_INDEX_MD


def test_settings_local_json_has_context_paths() -> None:
    """CLAUDE_SETTINGS_LOCAL_JSON includes contextPaths with .ievo/iEVO.md."""
    data = json.loads(CLAUDE_SETTINGS_LOCAL_JSON)
    assert "contextPaths" in data
    assert data["contextPaths"] == [".ievo/iEVO.md"]
    assert "PreCompact" in data["hooks"]


def test_gitignore_non_empty() -> None:
    assert ".env" in GITIGNORE
    assert "__pycache__" in GITIGNORE
    assert len(GITIGNORE.strip()) > 50


def test_claude_md_has_sections() -> None:
    assert "Tech stack" in CLAUDE_MD
    assert "Conventions" in CLAUDE_MD
    assert "{project_name}" in CLAUDE_MD
    assert "What this project is" in CLAUDE_MD
    assert "What NOT to do" in CLAUDE_MD


def test_all_templates_non_empty() -> None:
    for name, template in [
        ("SPEC_INDEX_MD", SPEC_INDEX_MD),
        ("CLAUDE_MD", CLAUDE_MD),
        ("GITIGNORE", GITIGNORE),
    ]:
        assert len(template.strip()) > 50, f"{name} is too short"


# ── Bundled marketplace template validation ──────────────────


def test_bundled_req_template_has_sections() -> None:
    """Bundled REQ_TEMPLATE.md has expected sections."""
    path = bundled_template_path("REQ_TEMPLATE.md")
    assert path is not None
    content = path.read_text()
    assert "Acceptance Criteria" in content
    assert "Metadata" in content


def test_bundled_cr_template_has_sections() -> None:
    """Bundled CHANGE_REQUEST_TEMPLATE.md has expected sections."""
    path = bundled_template_path("CHANGE_REQUEST_TEMPLATE.md")
    assert path is not None
    content = path.read_text()
    assert "What Changes" in content


def test_bundled_templates_removed_from_init_templates() -> None:
    """SPEC_REQ_TEMPLATE and SPEC_CR_TEMPLATE no longer in init_templates."""
    import ievo.commands.init_templates as tpl

    assert not hasattr(tpl, "SPEC_REQ_TEMPLATE")
    assert not hasattr(tpl, "SPEC_CR_TEMPLATE")


# ── ievo.core.templates: TEMPLATE_MAP ────────────────────────


def test_template_map_has_seven_entries() -> None:
    """TEMPLATE_MAP has exactly 7 entries (IEVO.md + 6 spec templates)."""
    from ievo.core.templates import TEMPLATE_MAP

    assert len(TEMPLATE_MAP) == 7


def test_template_map_ievo_md_destination() -> None:
    """iEVO.md deploys to .ievo/iEVO.md."""
    from ievo.core.templates import TEMPLATE_MAP

    assert ("iEVO.md", ".ievo/iEVO.md") in TEMPLATE_MAP


def test_template_map_req_template_destination() -> None:
    """REQ_TEMPLATE.md deploys to spec/templates/REQ_TEMPLATE.md."""
    from ievo.core.templates import TEMPLATE_MAP

    assert ("REQ_TEMPLATE.md", "spec/templates/REQ_TEMPLATE.md") in TEMPLATE_MAP


# ── ievo.core.templates: refresh_templates ───────────────────


def _make_template_project(root: Path) -> None:
    """Create a minimal project with manifest for template tests."""
    (root / ".ievo").mkdir(parents=True, exist_ok=True)
    manifest_data = {"project": "test", "version": "0.1.0", "cli_version": "0.0.1"}
    (root / ".ievo" / "manifest.yaml").write_text(yaml.dump(manifest_data, sort_keys=False))


def test_refresh_templates_copies_all_files(tmp_path: Path) -> None:
    """refresh_templates copies all 7 templates; stale content is overwritten."""
    from ievo.core.templates import TEMPLATE_MAP, refresh_templates

    _make_template_project(tmp_path)

    # Write stale content to destinations
    for _bundled, dest_rel in TEMPLATE_MAP:
        dest = tmp_path / dest_rel
        dest.parent.mkdir(parents=True, exist_ok=True)
        dest.write_text("stale content")

    count = refresh_templates(tmp_path, "0.2.0")

    assert count == 7
    for _bundled_name, dest_rel in TEMPLATE_MAP:
        dest = tmp_path / dest_rel
        assert dest.exists(), f"Expected {dest_rel} to exist after refresh"
        content = dest.read_text()
        assert content != "stale content", f"{dest_rel} still has stale content"


def test_refresh_templates_updates_cli_version(tmp_path: Path) -> None:
    """After refresh_templates(), manifest.cli_version == passed version."""
    from ievo.core.project import ProjectManifest
    from ievo.core.templates import refresh_templates

    _make_template_project(tmp_path)
    refresh_templates(tmp_path, "0.2.0")

    manifest = ProjectManifest.load(tmp_path)
    assert manifest.cli_version == "0.2.0"


def test_refresh_templates_creates_missing_dirs(tmp_path: Path) -> None:
    """refresh_templates creates destination directories if they don't exist."""
    from ievo.core.templates import refresh_templates

    _make_template_project(tmp_path)
    # Do NOT pre-create spec/templates/

    refresh_templates(tmp_path, "0.2.0")

    assert (tmp_path / "spec" / "templates").is_dir()
    assert (tmp_path / ".ievo" / "iEVO.md").exists()


def test_refresh_templates_skips_missing_bundled(tmp_path: Path) -> None:
    """refresh_templates skips templates whose bundled source returns None, no crash."""
    from ievo.core.templates import refresh_templates
    from ievo.marketplace import bundled_template_path as _btp

    _make_template_project(tmp_path)

    original = _btp

    def patched(filename: str):
        if filename == "iEVO.md":
            return None  # simulate missing bundled file
        return original(filename)

    with patch("ievo.core.templates.bundled_template_path", side_effect=patched):
        count = refresh_templates(tmp_path, "0.2.0")

    # Only 6 files copied (IEVO.md skipped)
    assert count == 6
    # iEVO.md should NOT exist
    assert not (tmp_path / ".ievo" / "iEVO.md").exists()
    # Other templates should exist
    assert (tmp_path / "spec" / "templates" / "REQ_TEMPLATE.md").exists()


def test_refresh_templates_returns_count(tmp_path: Path) -> None:
    """refresh_templates returns the number of templates actually copied."""
    from ievo.core.templates import refresh_templates

    _make_template_project(tmp_path)
    count = refresh_templates(tmp_path, "0.2.0")
    assert count == 7
