"""Tests for Drata GRC evidence exporter."""

from __future__ import annotations

import json
from typing import TYPE_CHECKING
from unittest.mock import AsyncMock, patch

import httpx
import pytest

from complyform.core.errors import ExportAPIAuthError
from complyform.core.generators.evidence_export.drata import DrataExporter

if TYPE_CHECKING:
    from pathlib import Path


@pytest.fixture
def exporter() -> DrataExporter:
    return DrataExporter()


@pytest.fixture
def metadata() -> dict[str, object]:
    return {"scan_id": "abc12345", "timestamp": "2024-01-01T00:00:00Z", "cloud": "aws"}


@pytest.fixture
def sample_findings() -> list[dict[str, object]]:
    return [
        {
            "control_id": "CC6.1",
            "framework": "soc2",
            "resource_address": "aws_s3_bucket.example",
            "resource_type": "aws_s3_bucket",
            "status": "FAIL",
            "severity": "HIGH",
            "finding": "Bucket encryption not enabled",
            "remediation": "Enable SSE",
        },
        {
            "control_id": "CC7.2",
            "framework": "soc2",
            "resource_address": "aws_s3_bucket.logs",
            "resource_type": "aws_s3_bucket",
            "status": "PASS",
            "severity": "MEDIUM",
            "finding": "Logging enabled",
            "remediation": "",
        },
    ]


@pytest.fixture
def api_config() -> dict[str, object]:
    return {"api_key": "test-api-key"}


class TestDrataExporter:
    def test_export_to_file(
        self,
        exporter: DrataExporter,
        sample_findings: list[dict[str, object]],
        metadata: dict[str, object],
        tmp_path: Path,
    ) -> None:
        result = exporter.export_to_file(sample_findings, metadata, tmp_path)
        assert result.format == "drata"
        assert result.record_count == 2
        assert len(result.output_files) == 1

        data = json.loads(result.output_files[0].read_text())
        assert data["platform"] == "drata"
        assert data["evidence_count"] == 2
        assert len(data["evidence"]) == 2
        # Drata uses PASSED/FAILED
        assert data["evidence"][0]["status"] == "FAILED"
        assert data["evidence"][1]["status"] == "PASSED"
        # Controls aggregation
        assert len(data["controls"]) == 2

    @pytest.mark.asyncio
    async def test_push_to_api_success(
        self,
        exporter: DrataExporter,
        sample_findings: list[dict[str, object]],
        metadata: dict[str, object],
        api_config: dict[str, object],
        tmp_path: Path,
    ) -> None:
        upload_response = httpx.Response(
            200,
            json={"id": "ev-1"},
            request=httpx.Request("POST", "https://public-api.drata.com/evidence"),
        )

        with (
            patch(
                "complyform.core.generators.evidence_export.drata.grc_request",
                new_callable=AsyncMock,
                return_value=upload_response,
            ),
            patch(
                "complyform.core.generators.evidence_export.drata._default_output_dir",
                return_value=tmp_path,
            ),
        ):
            result = await exporter.push_to_api(sample_findings, metadata, api_config)
            assert result.api_push_status == "success"
            assert result.record_count == 2

    def test_push_to_api_control_mapping(
        self,
        exporter: DrataExporter,
        sample_findings: list[dict[str, object]],
        metadata: dict[str, object],
        tmp_path: Path,
    ) -> None:
        """Verify control aggregation in file export."""
        result = exporter.export_to_file(sample_findings, metadata, tmp_path)
        data = json.loads(result.output_files[0].read_text())
        controls = {c["control_id"]: c for c in data["controls"]}
        assert "CC6.1" in controls
        assert "CC7.2" in controls
        assert controls["CC6.1"]["fail_count"] == 1
        assert controls["CC7.2"]["pass_count"] == 1

    @pytest.mark.asyncio
    async def test_push_to_api_auth_failure(
        self,
        exporter: DrataExporter,
        sample_findings: list[dict[str, object]],
        metadata: dict[str, object],
        api_config: dict[str, object],
        tmp_path: Path,
    ) -> None:
        with (
            patch(
                "complyform.core.generators.evidence_export.drata.grc_request",
                new_callable=AsyncMock,
                side_effect=ExportAPIAuthError("drata"),
            ),
            patch(
                "complyform.core.generators.evidence_export.drata._default_output_dir",
                return_value=tmp_path,
            ),
        ):
            from complyform.core.errors import ExportAPIPushError

            with pytest.raises(ExportAPIPushError):
                await exporter.push_to_api(sample_findings, metadata, api_config)
