"""Tests for complyform.core.cache."""

from __future__ import annotations

import json
from typing import TYPE_CHECKING

from complyform.core.cache import ScanCache

if TYPE_CHECKING:
    from pathlib import Path
from complyform.core.scanner.state_parser import (
    ResourceRecord,
    StateMetadata,
)


def _make_resources() -> list[ResourceRecord]:
    return [
        ResourceRecord(
            provider="google",
            resource_type="google_storage_bucket",
            name="test",
            address="google_storage_bucket.test",
            attributes={"id": "bucket-1", "name": "test"},
            module=None,
            source_state="test",
        )
    ]


def _make_metadata() -> StateMetadata:
    return StateMetadata(
        terraform_version="1.9.0",
        provider_versions={},
        serial=1,
        lineage="test-lineage",
    )


class TestWriteAndRead:
    def test_round_trip(self, tmp_path: Path) -> None:
        cache = ScanCache(cache_dir=tmp_path / "cache")
        content = b'{"version": 4}'
        resources = _make_resources()
        meta = _make_metadata()

        key = cache.write(content, "./test.tfstate", "gcp", resources, meta)
        assert len(key) == 16

        result = cache.read(key)
        assert result is not None
        loaded_resources, loaded_meta = result
        assert len(loaded_resources) == 1
        assert loaded_resources[0].name == "test"
        assert loaded_meta["cloud"] == "gcp"
        assert loaded_meta["resource_count"] == 1


class TestReadExpired:
    def test_expired_returns_none(self, tmp_path: Path) -> None:
        cache = ScanCache(cache_dir=tmp_path / "cache")
        content = b"expired-content"
        resources = _make_resources()
        meta = _make_metadata()

        key = cache.write(content, "./test.tfstate", "gcp", resources, meta)

        # Tamper with scanned_at to be >1 hour ago
        meta_path = tmp_path / "cache" / key / "metadata.json"
        meta_data = json.loads(meta_path.read_text(encoding="utf-8"))
        meta_data["scanned_at"] = "2020-01-01T00:00:00+00:00"
        meta_path.write_text(json.dumps(meta_data), encoding="utf-8")

        result = cache.read(key)
        assert result is None


class TestReadMissing:
    def test_nonexistent_returns_none(self, tmp_path: Path) -> None:
        cache = ScanCache(cache_dir=tmp_path / "cache")
        assert cache.read("nonexistent12345") is None


class TestWriteOverwrites:
    def test_overwrites_existing(self, tmp_path: Path) -> None:
        cache = ScanCache(cache_dir=tmp_path / "cache")
        content = b"same-content"

        r1 = [
            ResourceRecord(
                provider="google",
                resource_type="google_storage_bucket",
                name="old",
                address="google_storage_bucket.old",
                attributes={},
                module=None,
                source_state="test",
            )
        ]
        r2 = [
            ResourceRecord(
                provider="google",
                resource_type="google_storage_bucket",
                name="new",
                address="google_storage_bucket.new",
                attributes={},
                module=None,
                source_state="test",
            )
        ]
        meta = _make_metadata()

        key = cache.write(content, "./test.tfstate", "gcp", r1, meta)
        cache.write(content, "./test.tfstate", "gcp", r2, meta)

        result = cache.read(key)
        assert result is not None
        assert result[0][0].name == "new"


class TestClear:
    def test_deletes_entry(self, tmp_path: Path) -> None:
        cache = ScanCache(cache_dir=tmp_path / "cache")
        content = b"to-delete"
        key = cache.write(
            content,
            "./test.tfstate",
            "gcp",
            _make_resources(),
            _make_metadata(),
        )
        cache.clear(key)
        assert cache.read(key) is None

    def test_clear_all(self, tmp_path: Path) -> None:
        cache = ScanCache(cache_dir=tmp_path / "cache")
        cache.write(
            b"a",
            "./a.tfstate",
            "gcp",
            _make_resources(),
            _make_metadata(),
        )
        cache.write(
            b"b",
            "./b.tfstate",
            "gcp",
            _make_resources(),
            _make_metadata(),
        )
        cache.clear_all()
        assert not (tmp_path / "cache").exists()


class TestCacheDirectoryCreation:
    def test_auto_creates(self, tmp_path: Path) -> None:
        cache_dir = tmp_path / "nested" / "cache"
        cache = ScanCache(cache_dir=cache_dir)
        cache.write(
            b"test",
            "./test.tfstate",
            "gcp",
            _make_resources(),
            _make_metadata(),
        )
        assert cache_dir.exists()


class TestReadByContent:
    def test_read_by_state_content(self, tmp_path: Path) -> None:
        cache = ScanCache(cache_dir=tmp_path / "cache")
        content = b"content-hash-test"
        cache.write(
            content,
            "./test.tfstate",
            "gcp",
            _make_resources(),
            _make_metadata(),
        )
        result = cache.read_by_state_content(content)
        assert result is not None
        assert len(result[0]) == 1
