"""Tests for module resource estimation (Phase 4)."""

from __future__ import annotations

from ilum.core.resources import (
    ResourceEstimate,
    check_resources_for_modules,
    estimate_total,
    format_estimate,
    get_module_estimate,
)


class TestResourceEstimate:
    def test_get_known_module(self) -> None:
        est = get_module_estimate("core")
        assert est.memory_mi == 2048
        assert est.cpu_millicores == 1000

    def test_get_unknown_module_returns_default(self) -> None:
        est = get_module_estimate("unknown-module")
        assert est.memory_mi == 128
        assert est.cpu_millicores == 100


class TestEstimateTotal:
    def test_single_module(self) -> None:
        total = estimate_total(["core"])
        assert total.memory_mi == 2048
        assert total.cpu_millicores == 1000

    def test_multiple_modules(self) -> None:
        total = estimate_total(["core", "ui", "mongodb"])
        assert total.memory_mi == 2048 + 256 + 512
        assert total.cpu_millicores == 1000 + 100 + 250

    def test_no_double_counting(self) -> None:
        total = estimate_total(["core", "core", "ui"])
        assert total.memory_mi == 2048 + 256

    def test_empty_list(self) -> None:
        total = estimate_total([])
        assert total.memory_mi == 0
        assert total.cpu_millicores == 0

    def test_reference_case_fits_12gib(self) -> None:
        """Default modules + sql + marquez + superset + jupyter + hive-metastore fits in 12 GiB."""
        modules = [
            "core",
            "ui",
            "mongodb",
            "minio",
            "postgresql",
            "gitea",  # defaults
            "jupyter",
            "sql",
            "marquez",
            "superset",
            "hive-metastore",
        ]
        total = estimate_total(modules)
        assert total.memory_mi <= 12 * 1024  # 12 GiB


class TestFormatEstimate:
    def test_gib_format(self) -> None:
        est = ResourceEstimate(memory_mi=2048, cpu_millicores=1000)
        result = format_estimate(est)
        assert "2.0 GiB" in result
        assert "1.0 CPU" in result

    def test_mib_format(self) -> None:
        est = ResourceEstimate(memory_mi=512, cpu_millicores=500)
        result = format_estimate(est)
        assert "512 MiB" in result
        assert "0.5 CPU" in result


class TestCheckResourcesForModules:
    def test_sufficient_resources(self) -> None:
        result = check_resources_for_modules(
            ["core", "ui"],
            cluster_resources={
                "allocatable_memory_bytes": 12 * 1024 * 1024 * 1024,
                "allocatable_cpu_millicores": 8000,
            },
        )
        assert result.sufficient is True
        assert result.utilization_pct is not None
        assert result.utilization_pct < 80

    def test_insufficient_resources(self) -> None:
        result = check_resources_for_modules(
            ["core", "ui", "mongodb", "kafka", "airflow", "trino", "monitoring"],
            cluster_resources={
                "allocatable_memory_bytes": 4 * 1024 * 1024 * 1024,
                "allocatable_cpu_millicores": 2000,
            },
        )
        assert result.sufficient is False
        assert "memory pressure" in result.message

    def test_unknown_cluster(self) -> None:
        result = check_resources_for_modules(
            ["core", "ui"],
            cluster_resources=None,
        )
        assert result.sufficient is True
        assert "unknown" in result.message.lower()

    def test_utilization_percentage(self) -> None:
        result = check_resources_for_modules(
            ["core"],  # 2048 MiB
            cluster_resources={
                "allocatable_memory_bytes": 4 * 1024 * 1024 * 1024,  # 4 GiB
                "allocatable_cpu_millicores": 4000,
            },
        )
        assert result.utilization_pct is not None
        assert 49 < result.utilization_pct < 51  # ~50%
