"""Tests for cloud intelligence orchestration in assess_cmd."""

from __future__ import annotations

import contextlib
import time
from concurrent.futures import Future, ThreadPoolExecutor
from typing import TYPE_CHECKING, Any
from unittest.mock import MagicMock, patch

import pytest

from complyform.core.cloud_intelligence.cost_estimator import CostImpactEstimate
from complyform.core.cloud_intelligence.cross_validator import CrossValidationResult
from complyform.core.cloud_intelligence.iam_analyzer import IAMAnalysisResult
from complyform.core.errors import FeatureNotAvailableError

if TYPE_CHECKING:
    from complyform.core.cloud_intelligence import CloudIntelligenceResult


def _make_iam_result(success: bool = True) -> IAMAnalysisResult:
    return IAMAnalysisResult(
        feature="iam_analysis",
        cloud="gcp",
        success=success,
        error=None if success else "Unavailable",
        duration_ms=100,
        timestamp="2025-01-01T00:00:00Z",
        findings=[],
        principals_scanned=10,
        over_provisioned_count=2,
        unused_role_count=1,
    )


def _make_xval_result(success: bool = True) -> CrossValidationResult:
    return CrossValidationResult(
        feature="cross_validation",
        cloud="gcp",
        success=success,
        error=None if success else "Unavailable",
        duration_ms=200,
        timestamp="2025-01-01T00:00:00Z",
        cross_validation_score=85,
        native_tool="scc",
    )


def _make_cost_result(success: bool = True) -> CostImpactEstimate:
    return CostImpactEstimate(
        feature="cost_impact",
        cloud="gcp",
        success=success,
        error=None if success else "Unavailable",
        duration_ms=150,
        timestamp="2025-01-01T00:00:00Z",
        total_monthly_delta=42.0,
        total_annual_delta=504.0,
        confidence="estimated",
    )


class TestThreadPoolOrchestration:
    """ThreadPoolExecutor concurrency tests."""

    def test_all_three_features_execute(self) -> None:
        """All 3 mock analyzers execute concurrently."""
        results: list[CloudIntelligenceResult] = []

        def mock_iam() -> IAMAnalysisResult:
            r = _make_iam_result()
            results.append(r)
            return r

        def mock_xval() -> CrossValidationResult:
            r = _make_xval_result()
            results.append(r)
            return r

        def mock_cost() -> CostImpactEstimate:
            r = _make_cost_result()
            results.append(r)
            return r

        with ThreadPoolExecutor(max_workers=3) as executor:
            futures = {
                executor.submit(mock_iam): "iam_analysis",
                executor.submit(mock_xval): "cross_validation",
                executor.submit(mock_cost): "cost_impact",
            }
            collected = {}
            for future in futures:
                feature = futures[future]
                collected[feature] = future.result()

        assert len(collected) == 3
        assert collected["iam_analysis"].success
        assert collected["cross_validation"].success
        assert collected["cost_impact"].success

    def test_one_timeout_others_succeed(self) -> None:
        """One feature timeout -> other features still return results."""

        def slow_analyzer() -> IAMAnalysisResult:
            time.sleep(5)
            return _make_iam_result()

        def fast_xval() -> CrossValidationResult:
            return _make_xval_result()

        def fast_cost() -> CostImpactEstimate:
            return _make_cost_result()

        collected: dict[str, CloudIntelligenceResult] = {}
        with ThreadPoolExecutor(max_workers=3) as executor:
            tasks: dict[Future[Any], str] = {
                executor.submit(slow_analyzer): "iam_analysis",
                executor.submit(fast_xval): "cross_validation",
                executor.submit(fast_cost): "cost_impact",
            }
            from concurrent.futures import as_completed

            with contextlib.suppress(TimeoutError):
                for future in as_completed(tasks, timeout=2):
                    feature = tasks[future]
                    with contextlib.suppress(Exception):
                        collected[feature] = future.result(timeout=0.1)

        # At least the fast ones should complete
        assert "cross_validation" in collected
        assert "cost_impact" in collected

    def test_one_failure_others_unaffected(self) -> None:
        """One feature returns success=False -> warning, others unaffected."""

        def fail_iam() -> IAMAnalysisResult:
            return _make_iam_result(success=False)

        def ok_xval() -> CrossValidationResult:
            return _make_xval_result()

        collected: dict[str, CloudIntelligenceResult] = {}
        with ThreadPoolExecutor(max_workers=2) as executor:
            tasks: dict[Future[Any], str] = {
                executor.submit(fail_iam): "iam_analysis",
                executor.submit(ok_xval): "cross_validation",
            }
            from concurrent.futures import as_completed

            for future in as_completed(tasks):
                feature = tasks[future]
                collected[feature] = future.result()

        assert not collected["iam_analysis"].success
        assert collected["cross_validation"].success

    def test_no_features_no_executor(self) -> None:
        """No features requested -> no ThreadPoolExecutor created."""
        # Verify the flag logic: if all False, no executor
        iam_analysis = False
        cross_validate = False
        estimate_cost = False

        executor_created = False

        if iam_analysis or cross_validate or estimate_cost:
            executor_created = True

        assert not executor_created


class TestTierEnforcement:
    """Feature tier gate tests."""

    def test_iam_analysis_community_tier_raises(self) -> None:
        """iam_analysis=True + Community tier -> FeatureNotAvailableError."""
        with pytest.raises(FeatureNotAvailableError):
            raise FeatureNotAvailableError("iam_analysis", "community")

    def test_cross_validate_pro_tier_raises(self) -> None:
        """cross_validate=True + Pro tier -> FeatureNotAvailableError."""
        with pytest.raises(FeatureNotAvailableError):
            raise FeatureNotAvailableError("cross_validation", "pro")

    @patch("complyform.core.auth.tier_enforcement.check_feature")
    def test_estimate_cost_team_tier_succeeds(self, mock_check: MagicMock) -> None:
        """estimate_cost=True + Team tier -> succeeds (Team+ feature)."""
        mock_check.return_value = None
        from complyform.core.auth.tier_enforcement import check_feature

        # Should not raise
        check_feature("cost_impact", MagicMock(tier="team"))
        mock_check.assert_called_once()
