"""Vanta GRC evidence exporter with OAuth2 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

VANTA_TOKEN_URL = "https://api.vanta.com/oauth/token"
VANTA_DOCUMENTS_URL = "https://api.vanta.com/v1/evidence/documents"


class VantaExporter(EvidenceExporter):
    """Export findings to Vanta format with optional API push."""

    FORMAT_ID = "vanta"
    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 Vanta-formatted JSON evidence file."""
        output_dir.mkdir(parents=True, exist_ok=True)
        scan_id = str(metadata.get("scan_id", "unknown"))

        documents: 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"))

            documents.append(
                {
                    "external_id": f"cf-{framework}-{control_id}-{resource_hash}",
                    "title": f"{framework} {control_id} - {resource_address}",
                    "description": str(finding.get("finding", "")),
                    "status": "PASS" if status == "PASS" else "FAIL",
                    "framework": framework,
                    "control_id": control_id,
                    "resource_type": str(finding.get("resource_type", "")),
                    "severity": str(finding.get("severity", "MEDIUM")),
                    "remediation": str(finding.get("remediation", "")),
                }
            )

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

        output_path = output_dir / f"complyform-vanta-{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(documents),
        )

    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 Vanta via OAuth2 API."""
        client_id = str(api_config.get("client_id", ""))
        client_secret = str(api_config.get("client_secret", ""))

        async with httpx.AsyncClient() as client:
            # OAuth2 token exchange
            token_resp = await grc_request(
                client,
                "POST",
                VANTA_TOKEN_URL,
                platform="vanta",
                json={
                    "grant_type": "client_credentials",
                    "client_id": client_id,
                    "client_secret": client_secret,
                    "scope": "connectors.self:write-resource",
                },
            )
            token_data = token_resp.json()
            access_token = token_data.get("access_token", "")

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

            headers = {"Authorization": f"Bearer {access_token}"}
            pushed = 0
            errors: list[str] = []

            for doc in _build_documents(findings, metadata):
                try:
                    await grc_request(
                        client,
                        "POST",
                        VANTA_DOCUMENTS_URL,
                        platform="vanta",
                        json=doc,
                        headers=headers,
                    )
                    pushed += 1
                except Exception as exc:
                    errors.append(str(exc))

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

        warnings = [f"Failed to push {len(errors)} document(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],
            },
            warnings=warnings,
        )


def _build_documents(
    findings: list[dict[str, object]],
    metadata: dict[str, object],
) -> list[dict[str, object]]:
    """Build document payloads for Vanta API."""
    documents: 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"))

        documents.append(
            {
                "external_id": f"cf-{framework}-{control_id}-{resource_hash}",
                "title": f"{framework} {control_id} - {resource_address}",
                "description": str(finding.get("finding", "")),
                "status": "PASS" if status == "PASS" else "FAIL",
            }
        )
    return documents


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

    return Path("./exports")
