"""Tests for complyform.core.scanner.multi_state."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

if TYPE_CHECKING:
    from pathlib import Path

from complyform.core.errors import MixedCloudMultiStateError
from complyform.core.scanner.multi_state import (
    compute_multi_state_cache_key,
    merge_state_inventories,
)
from complyform.core.scanner.state_parser import ResourceRecord, StateMetadata


def _make_resource(
    address: str,
    source_state: str = "default",
    provider: str = "google",
) -> ResourceRecord:
    return ResourceRecord(
        provider=provider,
        resource_type="google_compute_instance",
        name="test",
        address=address,
        attributes={},
        source_state=source_state,
    )


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


class TestMergeStateInventories:
    def test_merge_two_gcp_inventories(self) -> None:
        inv1 = (
            "prod",
            [_make_resource(f"res_{i}", "prod") for i in range(5)],
            _make_metadata(1),
        )
        inv2 = (
            "staging",
            [_make_resource(f"res_{i}", "staging") for i in range(5)],
            _make_metadata(2),
        )
        merged, all_meta = merge_state_inventories([inv1, inv2])
        assert len(merged) == 10
        assert len(all_meta) == 2

    def test_mixed_cloud_raises(self) -> None:
        inv1 = (
            "gcp-prod",
            [_make_resource("res_0", "gcp-prod", provider="google")],
            _make_metadata(),
        )
        inv2 = (
            "aws-prod",
            [_make_resource("res_1", "aws-prod", provider="aws")],
            _make_metadata(),
        )
        with pytest.raises(MixedCloudMultiStateError) as exc_info:
            merge_state_inventories([inv1, inv2])
        assert "aws" in exc_info.value.message
        assert "gcp" in exc_info.value.message

    def test_single_inventory_passthrough(self) -> None:
        inv = (
            "only",
            [_make_resource("res_0", "only")],
            _make_metadata(),
        )
        merged, all_meta = merge_state_inventories([inv])
        assert len(merged) == 1
        assert len(all_meta) == 1

    def test_deduplication_keeps_last(self) -> None:
        r1 = _make_resource("same_addr", "same_source")
        r2 = _make_resource("same_addr", "same_source")
        r2_attrs = {"updated": True}
        r2 = ResourceRecord(
            provider="google",
            resource_type="google_compute_instance",
            name="test",
            address="same_addr",
            attributes=r2_attrs,
            source_state="same_source",
        )
        inv1 = ("src", [r1], _make_metadata())
        inv2 = ("src", [r2], _make_metadata())
        merged, _ = merge_state_inventories([inv1, inv2])
        assert len(merged) == 1
        assert merged[0].attributes == {"updated": True}


class TestComputeMultiStateCacheKey:
    def test_deterministic(self, tmp_path: Path) -> None:
        (tmp_path / "a.tfstate").write_text('{"version":4}')
        (tmp_path / "b.tfstate").write_text('{"version":4,"serial":1}')
        paths = [tmp_path / "a.tfstate", tmp_path / "b.tfstate"]
        key1 = compute_multi_state_cache_key(paths)
        key2 = compute_multi_state_cache_key(list(reversed(paths)))
        assert key1 == key2
        assert len(key1) == 16

    def test_different_content_different_key(self, tmp_path: Path) -> None:
        (tmp_path / "a.tfstate").write_text('{"version":4}')
        (tmp_path / "b.tfstate").write_text('{"version":4,"serial":2}')
        key1 = compute_multi_state_cache_key([tmp_path / "a.tfstate"])

        (tmp_path / "a.tfstate").write_text('{"version":4,"serial":99}')
        key2 = compute_multi_state_cache_key([tmp_path / "a.tfstate"])
        assert key1 != key2
