"""complyform-dr-test — quarterly disaster recovery restore verification.

Trigger: Quarterly Cloud Scheduler.

Triggers a Firestore import to the staging project (``complyform-dr``),
waits for completion, queries the document count, and compares against the
expected count from the last backup verify.

Contract: this is a destructive operation on the staging project.
Uses ADC with cross-project permissions.  Always returns 200.
"""

from __future__ import annotations

import asyncio
import logging
from datetime import UTC, datetime
from typing import Any

from backend.ops._shared import cloud_function_wrapper, log_action, send_alert_email
from backend.shared.firestore import get_db

_log = logging.getLogger(__name__)

_STAGING_PROJECT = "complyform-dr"
_DR_BUCKET = "complyform-dr-exports"
_EXPORT_PREFIX = "firestore-exports/"
_POLL_INTERVAL_SECONDS = 30
_MAX_POLL_ATTEMPTS = 60  # 30 minutes max


@cloud_function_wrapper("complyform-dr-test")
async def dr_test(request: Any) -> dict[str, Any]:
    """Disaster recovery restore verification."""
    from google.cloud import firestore_admin_v1

    db = get_db()

    # 1. Get expected blob from last backup_verify
    verify_doc = await db.collection("founder_metrics").document("backup_verify").get()
    if not verify_doc.exists:
        await send_alert_email(
            subject="[ComplyForm] DR Test FAILED — no backup_verify record",
            body=(
                "Cannot run DR test: no backup_verify document "
                "found in founder_metrics."
            ),
        )
        log_action(customer_id=None, action="dr_test_fail", error="no_backup_verify")
        return {"status": "fail", "reason": "no_backup_verify"}

    verify_data = verify_doc.to_dict() or {}
    latest_blob = verify_data.get("latest_blob", "")
    expected_size = verify_data.get("latest_size", 0)

    if not latest_blob:
        await send_alert_email(
            subject="[ComplyForm] DR Test FAILED — no export blob recorded",
            body="backup_verify document exists but latest_blob is empty.",
        )
        log_action(customer_id=None, action="dr_test_fail", error="no_blob_recorded")
        return {"status": "fail", "reason": "no_blob_recorded"}

    # 2. Trigger Firestore import to staging
    admin_client = firestore_admin_v1.FirestoreAdminClient()
    database_name = f"projects/{_STAGING_PROJECT}/databases/(default)"

    # The import input URI should be the parent directory of the export
    blob_parts = latest_blob.rsplit("/", 1)
    input_uri = (
        f"gs://{_DR_BUCKET}/{blob_parts[0]}/"
        if len(blob_parts) > 1
        else f"gs://{_DR_BUCKET}/{latest_blob}"
    )

    try:
        operation = admin_client.import_documents(
            request={
                "name": database_name,
                "input_uri_prefix": input_uri,
            }
        )
    except Exception as exc:
        await send_alert_email(
            subject="[ComplyForm] DR Test FAILED — import trigger error",
            body=f"Failed to trigger Firestore import:\n{exc}",
        )
        log_action(customer_id=None, action="dr_test_fail", error=str(exc))
        return {"status": "fail", "reason": f"import_trigger_error: {exc}"}

    # 3. Poll for completion
    log_action(
        customer_id=None,
        action="dr_test_import_started",
        operation=operation.operation.name,
    )

    for _attempt in range(_MAX_POLL_ATTEMPTS):
        if operation.done():
            break
        await asyncio.sleep(_POLL_INTERVAL_SECONDS)
        operation = admin_client.get_operation(
            request={"name": operation.operation.name}
        )

    if not operation.done():
        await send_alert_email(
            subject="[ComplyForm] DR Test FAILED — import timeout",
            body=(
                f"Import operation did not complete within "
                f"{_MAX_POLL_ATTEMPTS * _POLL_INTERVAL_SECONDS // 60} minutes."
            ),
        )
        log_action(customer_id=None, action="dr_test_fail", error="import_timeout")
        return {"status": "fail", "reason": "import_timeout"}

    # 4. Query document count in staging
    try:
        from google.cloud.firestore_v1 import AsyncClient

        staging_db = AsyncClient(project=_STAGING_PROJECT)
        doc_count = 0
        async for collection in staging_db.collections():
            async for _ in collection.stream():
                doc_count += 1
    except Exception as exc:
        await send_alert_email(
            subject="[ComplyForm] DR Test FAILED — staging query error",
            body=f"Failed to count documents in staging:\n{exc}",
        )
        log_action(customer_id=None, action="dr_test_fail", error=str(exc))
        return {"status": "fail", "reason": f"staging_query_error: {exc}"}

    # 5. Report
    now = datetime.now(UTC)
    result_status = "pass" if doc_count > 0 else "fail"

    report_lines = [
        "Disaster Recovery Test Report",
        "=" * 40,
        f"Date: {now.strftime('%Y-%m-%d %H:%M UTC')}",
        f"Source export: {latest_blob}",
        f"Export size: {expected_size:,} bytes",
        f"Staging project: {_STAGING_PROJECT}",
        f"Documents restored: {doc_count:,}",
        f"Status: {result_status.upper()}",
    ]

    subject_status = "PASSED" if result_status == "pass" else "FAILED"
    await send_alert_email(
        subject=f"[ComplyForm] DR Test {subject_status}",
        body="\n".join(report_lines),
    )

    # Record result
    await (
        db.collection("founder_metrics")
        .document("dr_test")
        .set(
            {
                "status": result_status,
                "doc_count": doc_count,
                "source_blob": latest_blob,
                "tested_at": now.isoformat(),
            }
        )
    )

    log_action(
        customer_id=None,
        action="dr_test_complete",
        status=result_status,
        doc_count=doc_count,
    )
    return {"status": result_status, "doc_count": doc_count}


entry_point = dr_test
