"""Tests for complyform.core.scanner.discovery."""

from __future__ import annotations

from pathlib import Path

import pytest

from complyform.core.errors import (
    DiscoverNoStatesFoundError,
    DiscoverTooManyStatesError,
)
from complyform.core.scanner.discovery import (
    derive_source_label,
    discover_state_files,
)


def _write_state(path: Path, content: str = '{"version":4}') -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(content, encoding="utf-8")


class TestDiscoverStateFiles:
    def test_happy_path_three_files(self, tmp_path: Path) -> None:
        for name in ["a.tfstate", "b.tfstate", "c.tfstate"]:
            _write_state(tmp_path / name)
        result = discover_state_files(tmp_path)
        assert len(result) == 3

    def test_pattern_override(self, tmp_path: Path) -> None:
        _write_state(tmp_path / "my.state")
        _write_state(tmp_path / "other.tfstate")
        result = discover_state_files(tmp_path, pattern="*.state")
        assert len(result) == 1
        assert result[0].name == "my.state"

    def test_empty_directory_raises(self, tmp_path: Path) -> None:
        with pytest.raises(DiscoverNoStatesFoundError):
            discover_state_files(tmp_path)

    def test_too_many_files_raises(self, tmp_path: Path) -> None:
        for i in range(51):
            _write_state(tmp_path / f"state_{i:03d}.tfstate")
        with pytest.raises(DiscoverTooManyStatesError) as exc_info:
            discover_state_files(tmp_path, limit=50)
        assert exc_info.value.error_code == 57

    def test_exactly_at_limit(self, tmp_path: Path) -> None:
        for i in range(50):
            _write_state(tmp_path / f"state_{i:03d}.tfstate")
        result = discover_state_files(tmp_path, limit=50)
        assert len(result) == 50

    def test_skips_hidden_dirs(self, tmp_path: Path) -> None:
        _write_state(tmp_path / ".terraform" / "state.tfstate")
        _write_state(tmp_path / "visible.tfstate")
        result = discover_state_files(tmp_path)
        assert len(result) == 1
        assert result[0].name == "visible.tfstate"

    def test_nested_discovery(self, tmp_path: Path) -> None:
        _write_state(tmp_path / "envs" / "prod" / "terraform.tfstate")
        _write_state(tmp_path / "envs" / "staging" / "terraform.tfstate")
        result = discover_state_files(tmp_path)
        assert len(result) == 2

    def test_skips_tiny_files(self, tmp_path: Path) -> None:
        (tmp_path / "empty.tfstate").write_text("")
        (tmp_path / "one_byte.tfstate").write_text("x")
        _write_state(tmp_path / "valid.tfstate")
        result = discover_state_files(tmp_path)
        assert len(result) == 1

    def test_sorted_output(self, tmp_path: Path) -> None:
        _write_state(tmp_path / "z.tfstate")
        _write_state(tmp_path / "a.tfstate")
        _write_state(tmp_path / "m.tfstate")
        result = discover_state_files(tmp_path)
        names = [p.name for p in result]
        assert names == sorted(names)

    def test_skips_node_modules(self, tmp_path: Path) -> None:
        _write_state(tmp_path / "node_modules" / "pkg" / "state.tfstate")
        _write_state(tmp_path / "real.tfstate")
        result = discover_state_files(tmp_path)
        assert len(result) == 1


class TestDeriveSourceLabel:
    def test_nested_path(self) -> None:
        label = derive_source_label(
            Path("envs/prod/terraform.tfstate"),
            Path("envs"),
        )
        # -terraform suffix is stripped by the label derivation logic
        assert label == "prod"

    def test_root_path(self) -> None:
        label = derive_source_label(
            Path("./terraform.tfstate"),
            Path("."),
        )
        assert label == "terraform"

    def test_deep_nesting(self) -> None:
        label = derive_source_label(
            Path("infra/gcp/prod/main.tfstate"),
            Path("infra"),
        )
        assert label == "gcp-prod-main"

    def test_lowercase(self) -> None:
        label = derive_source_label(
            Path("Envs/PROD/state.tfstate"),
            Path("Envs"),
        )
        assert label == "prod-state"
