"""Tests for Infracost subprocess runner."""

from __future__ import annotations

import json
from unittest.mock import MagicMock, patch

from complyform.core.cloud_intelligence.infracost_runner import (
    run_infracost_breakdown,
    run_infracost_diff,
)


class TestRunInfracostBreakdown:
    def test_binary_not_found(self) -> None:
        with patch("shutil.which", return_value=None):
            result = run_infracost_breakdown("/tmp/tf")
        assert result is None

    def test_timeout(self) -> None:
        import subprocess

        with (
            patch("shutil.which", return_value="/usr/bin/infracost"),
            patch(
                "subprocess.run",
                side_effect=subprocess.TimeoutExpired("cmd", 120),
            ),
        ):
            result = run_infracost_breakdown("/tmp/tf", timeout=1)
        assert result is None

    def test_nonzero_exit(self) -> None:
        mock_result = MagicMock()
        mock_result.returncode = 1
        mock_result.stderr = "some error"
        with (
            patch("shutil.which", return_value="/usr/bin/infracost"),
            patch("subprocess.run", return_value=mock_result),
        ):
            result = run_infracost_breakdown("/tmp/tf")
        assert result is None

    def test_valid_json(self) -> None:
        output = json.dumps({"projects": []})
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = output
        with (
            patch("shutil.which", return_value="/usr/bin/infracost"),
            patch("subprocess.run", return_value=mock_result),
        ):
            result = run_infracost_breakdown("/tmp/tf")
        assert result == {"projects": []}

    def test_invalid_json(self) -> None:
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = "not json"
        with (
            patch("shutil.which", return_value="/usr/bin/infracost"),
            patch("subprocess.run", return_value=mock_result),
        ):
            result = run_infracost_breakdown("/tmp/tf")
        assert result is None

    def test_temp_dir_cleanup(self) -> None:
        with (
            patch("shutil.which", return_value="/usr/bin/infracost"),
            patch("subprocess.run", side_effect=Exception("boom")),
            patch("shutil.rmtree") as mock_rmtree,
        ):
            run_infracost_breakdown("/tmp/tf")
            mock_rmtree.assert_called_once()


class TestRunInfracostDiff:
    def test_binary_not_found(self) -> None:
        with patch("shutil.which", return_value=None):
            result = run_infracost_diff("/tmp/patched", "/tmp/baseline.json")
        assert result is None

    def test_valid_json(self) -> None:
        output = json.dumps({"diffTotalMonthlyCost": "10.00"})
        mock_result = MagicMock()
        mock_result.returncode = 0
        mock_result.stdout = output
        with (
            patch("shutil.which", return_value="/usr/bin/infracost"),
            patch("subprocess.run", return_value=mock_result),
        ):
            result = run_infracost_diff("/tmp/p", "/tmp/b.json")
        assert result == {"diffTotalMonthlyCost": "10.00"}
