"""Tests for the project consistency checker."""

from __future__ import annotations

from pathlib import Path

from prisme.tracking.checker import ProjectChecker
from prisme.tracking.manifest import FileManifest, ManifestManager, TrackedFile


def _setup_manifest(project_dir: Path, manifest: FileManifest) -> None:
    """Helper to save a manifest to the project directory."""
    ManifestManager.save(manifest, project_dir)


def test_no_issues_empty_project(tmp_path: Path):
    """Test that a project with no manifest reports no issues."""
    checker = ProjectChecker(tmp_path)
    result = checker.run_all_checks()
    assert result.ok
    assert len(result.issues) == 0


def test_rogue_file_in_generated_dir(tmp_path: Path):
    """Test detection of untracked files in _generated/ directories."""
    manifest = FileManifest()
    manifest.track_file(
        TrackedFile(
            path="src/app/services/_generated/customer_base.py",
            strategy="always_overwrite",
            content_hash="abc",
            generated_at="2026-01-01T00:00:00",
        )
    )
    _setup_manifest(tmp_path, manifest)

    # Create the tracked file
    gen_dir = tmp_path / "src" / "app" / "services" / "_generated"
    gen_dir.mkdir(parents=True)
    (gen_dir / "customer_base.py").write_text("# generated")

    # Create a rogue file
    (gen_dir / "my_custom_service.py").write_text("# manually created")

    checker = ProjectChecker(tmp_path)
    result = checker.run_all_checks()

    rogue = [i for i in result.issues if i.category == "rogue_file"]
    assert len(rogue) == 1
    assert "my_custom_service.py" in rogue[0].path


def test_broken_extension(tmp_path: Path):
    """Test detection of extension files with missing base."""
    manifest = FileManifest()
    manifest.track_file(
        TrackedFile(
            path="src/app/services/customer.py",
            strategy="generate_once",
            content_hash="abc",
            generated_at="2026-01-01T00:00:00",
            extends="src/app/services/_generated/customer_base.py",
        )
    )
    _setup_manifest(tmp_path, manifest)

    # Don't create the base file — it's missing

    checker = ProjectChecker(tmp_path)
    result = checker.run_all_checks()

    broken = [i for i in result.issues if i.category == "broken_extension"]
    assert len(broken) == 1
    assert broken[0].level == "error"
    assert "customer_base.py" in broken[0].message


def test_orphaned_override(tmp_path: Path):
    """Test detection of overrides for deleted files."""
    from prisme.tracking.logger import Override, OverrideLog, OverrideLogger

    log = OverrideLog()
    log.add_override(
        Override(
            path="src/app/services/deleted.py",
            strategy="generate_once",
            timestamp="2026-01-01T00:00:00",
            generated_hash="abc",
            user_hash="def",
        )
    )
    OverrideLogger.save(log, tmp_path)

    checker = ProjectChecker(tmp_path)
    result = checker.run_all_checks()

    orphaned = [i for i in result.issues if i.category == "orphaned_override"]
    assert len(orphaned) == 1
    assert "deleted.py" in orphaned[0].path


def test_spec_changed(tmp_path: Path):
    """Test detection when spec has changed since last generation."""
    from prisme.tracking.manifest import hash_content

    spec_dir = tmp_path / "specs"
    spec_dir.mkdir()
    spec_file = spec_dir / "models.py"
    spec_file.write_text("# original spec")

    manifest = FileManifest()
    manifest.domain_hash = hash_content("# original spec")
    _setup_manifest(tmp_path, manifest)

    # Modify the spec
    spec_file.write_text("# modified spec")

    # Create prisme.toml pointing to the spec
    toml = tmp_path / "prisme.toml"
    toml.write_text('[project]\nspec_path = "specs/models.py"\nproject_path = "specs/project.py"\n')

    checker = ProjectChecker(tmp_path)
    result = checker.run_all_checks()

    spec_issues = [i for i in result.issues if i.category == "spec_changed"]
    assert len(spec_issues) == 1
    assert "prism generate" in spec_issues[0].message


def test_all_checks_combined(tmp_path: Path):
    """Test that all checks run and accumulate issues."""
    manifest = FileManifest()
    manifest.track_file(
        TrackedFile(
            path="src/services/_generated/base.py",
            strategy="always_overwrite",
            content_hash="abc",
            generated_at="2026-01-01T00:00:00",
        )
    )
    manifest.track_file(
        TrackedFile(
            path="src/services/ext.py",
            strategy="generate_once",
            content_hash="def",
            generated_at="2026-01-01T00:00:00",
            extends="src/services/_generated/missing_base.py",
        )
    )
    _setup_manifest(tmp_path, manifest)

    # Create _generated dir with rogue file
    gen_dir = tmp_path / "src" / "services" / "_generated"
    gen_dir.mkdir(parents=True)
    (gen_dir / "base.py").write_text("# ok")
    (gen_dir / "rogue.py").write_text("# bad")

    checker = ProjectChecker(tmp_path)
    result = checker.run_all_checks()

    # Should have at least a rogue file warning and a broken extension error
    assert not result.ok  # broken extension is an error
    categories = {i.category for i in result.issues}
    assert "rogue_file" in categories
    assert "broken_extension" in categories
