"""Secureframe GRC evidence exporter with multi-region API push."""

from __future__ import annotations

import hashlib
import json
from typing import TYPE_CHECKING, Any

import httpx

from complyform.core.errors import ExportAPIPushError
from complyform.core.generators.evidence_export._grc_http import grc_request
from complyform.core.generators.evidence_export.base import (
    EvidenceExporter,
    ExportResult,
)

if TYPE_CHECKING:
    from pathlib import Path

SECUREFRAME_REGION_URLS: dict[str, str] = {
    "us": "https://app.secureframe.com/api",
    "uk": "https://app-uk.secureframe.com/api",
    "eu": "https://app-eu.secureframe.com/api",
}

DEFAULT_REGION = "us"


class SecureframeExporter(EvidenceExporter):
    """Export findings to Secureframe format with optional API push."""

    FORMAT_ID = "secureframe"
    TIER_FEATURE = "evidence_export_grc"
    SUPPORTS_API_PUSH = True

    def export_to_file(
        self,
        findings: list[dict[str, object]],
        metadata: dict[str, object],
        output_dir: Path,
        project_label: str | None = None,
    ) -> ExportResult:
        """Generate Secureframe-formatted JSON evidence file."""
        output_dir.mkdir(parents=True, exist_ok=True)
        scan_id = str(metadata.get("scan_id", "unknown"))

        tests: list[dict[str, object]] = []
        for finding in findings:
            resource_address = str(finding.get("resource_address", ""))
            resource_hash = hashlib.sha256(resource_address.encode()).hexdigest()[:8]
            control_id = str(finding.get("control_id", ""))
            framework = str(finding.get("framework", ""))
            status = str(finding.get("status", "FAIL"))

            tests.append(
                {
                    "external_id": f"cf-{framework}-{control_id}-{resource_hash}",
                    "test_name": f"{framework} {control_id}",
                    "resource_name": resource_address,
                    "resource_type": str(finding.get("resource_type", "")),
                    "passing": status == "PASS",
                    "evidence_type": "pass" if status == "PASS" else "fail",
                    "framework": framework,
                    "control_id": control_id,
                    "severity": str(finding.get("severity", "MEDIUM")),
                    "description": str(finding.get("finding", "")),
                    "remediation": str(finding.get("remediation", "")),
                }
            )

        envelope: dict[str, Any] = {
            "schema_version": 1,
            "platform": "secureframe",
            "scan_id": scan_id,
            "timestamp": str(metadata.get("timestamp", "")),
            "cloud": str(metadata.get("cloud", "")),
            "project_label": project_label,
            "test_count": len(tests),
            "tests": tests,
        }

        output_path = output_dir / f"complyform-secureframe-{scan_id}.json"
        output_path.write_text(json.dumps(envelope, indent=2), encoding="utf-8")

        return ExportResult(
            format=self.FORMAT_ID,
            output_files=[output_path],
            record_count=len(tests),
        )

    async def push_to_api(  # type: ignore[override]
        self,
        findings: list[dict[str, object]],
        metadata: dict[str, object],
        api_config: dict[str, object],
    ) -> ExportResult:
        """Push findings to Secureframe API."""
        api_key = str(api_config.get("api_key", ""))
        api_secret = str(api_config.get("api_secret", ""))
        region = str(api_config.get("region", DEFAULT_REGION))

        base_url = SECUREFRAME_REGION_URLS.get(region, SECUREFRAME_REGION_URLS["us"])
        tests_url = f"{base_url}/tests"

        async with httpx.AsyncClient() as client:
            headers = {
                "X-API-Key": api_key,
                "X-API-Secret": api_secret,
            }

            file_result = self.export_to_file(
                findings,
                metadata,
                output_dir=_default_output_dir(),
            )

            pushed = 0
            errors: list[str] = []

            for test in _build_tests(findings, metadata):
                try:
                    await grc_request(
                        client,
                        "POST",
                        tests_url,
                        platform="secureframe",
                        json=test,
                        headers=headers,
                    )
                    pushed += 1
                except Exception as exc:
                    errors.append(str(exc))

        if errors and pushed == 0:
            raise ExportAPIPushError("secureframe", "; ".join(errors[:3]))

        warnings = [f"Failed to push {len(errors)} test(s)"] if errors else []

        return ExportResult(
            format=self.FORMAT_ID,
            output_files=file_result.output_files,
            record_count=pushed,
            api_push_status="partial" if errors else "success",
            api_push_details={
                "pushed": pushed,
                "failed": len(errors),
                "errors": errors[:5],
                "region": region,
                "base_url": base_url,
            },
            warnings=warnings,
        )


def _build_tests(
    findings: list[dict[str, object]],
    metadata: dict[str, object],
) -> list[dict[str, object]]:
    """Build test payloads for Secureframe API."""
    tests: list[dict[str, object]] = []
    for finding in findings:
        resource_address = str(finding.get("resource_address", ""))
        resource_hash = hashlib.sha256(resource_address.encode()).hexdigest()[:8]
        control_id = str(finding.get("control_id", ""))
        framework = str(finding.get("framework", ""))
        status = str(finding.get("status", "FAIL"))

        tests.append(
            {
                "external_id": f"cf-{framework}-{control_id}-{resource_hash}",
                "test_name": f"{framework} {control_id}",
                "passing": status == "PASS",
                "evidence_type": "pass" if status == "PASS" else "fail",
                "description": str(finding.get("finding", "")),
            }
        )
    return tests


def _default_output_dir() -> Path:
    from pathlib import Path

    return Path("./exports")
