"""Firestore async client — customer and license CRUD.

Collections:
- ``customers/{customer_id}``
- ``customers/{customer_id}/consent/``
- ``license_keys/{key_hash}``
- ``api_keys/{key_hash}``
- ``processed_webhook_events/{event_id}``
"""

from __future__ import annotations

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

if TYPE_CHECKING:
    from google.cloud.firestore_v1 import AsyncClient

_log = logging.getLogger(__name__)

_db: AsyncClient | None = None


def get_db() -> AsyncClient:
    """Return a module-level async Firestore client (singleton)."""
    global _db  # noqa: PLW0603
    if _db is None:
        from google.cloud.firestore_v1 import AsyncClient

        _db = AsyncClient(project="complyform-prod")
    return _db


# ---------------------------------------------------------------------------
# Idempotency
# ---------------------------------------------------------------------------


async def is_event_processed(event_id: str) -> bool:
    """Check whether a Paddle webhook event has already been handled."""
    doc = await get_db().collection("processed_webhook_events").document(event_id).get()
    return doc.exists


async def mark_event_processed(event_id: str, event_type: str) -> None:
    """Record a processed webhook event with Firestore TTL-targeted timestamp."""
    await (
        get_db()
        .collection("processed_webhook_events")
        .document(event_id)
        .set(
            {
                "event_type": event_type,
                "created_at": datetime.now(UTC),
            }
        )
    )


# ---------------------------------------------------------------------------
# Customer CRUD
# ---------------------------------------------------------------------------


async def get_customer(customer_id: str) -> dict[str, Any] | None:
    """Fetch customer doc. Returns ``None`` if not found."""
    doc = await get_db().collection("customers").document(customer_id).get()
    return doc.to_dict() if doc.exists else None


async def get_customer_by_subscription(
    subscription_id: str,
) -> tuple[str, dict[str, Any]] | None:
    """Find customer by ``paddle_subscription_id``.

    Returns ``(customer_id, data)`` or ``None``.
    """
    query = (
        get_db()
        .collection("customers")
        .where("paddle_subscription_id", "==", subscription_id)
        .limit(1)
    )
    docs = [doc async for doc in query.stream()]
    if not docs:
        return None
    return docs[0].id, docs[0].to_dict()  # type: ignore[return-value]


async def get_customer_by_email(email: str) -> tuple[str, dict[str, Any]] | None:
    """Find active customer by email.

    Returns ``(customer_id, data)`` or ``None``.
    """
    query = (
        get_db()
        .collection("customers")
        .where("email", "==", email)
        .where("status", "==", "active")
        .limit(1)
    )
    docs = [doc async for doc in query.stream()]
    if not docs:
        return None
    return docs[0].id, docs[0].to_dict()  # type: ignore[return-value]


async def create_customer(customer_id: str, data: dict[str, Any]) -> None:
    """Create or overwrite a customer document."""
    await get_db().collection("customers").document(customer_id).set(data)


async def update_customer(customer_id: str, fields: dict[str, Any]) -> None:
    """Merge-update fields on an existing customer document."""
    await get_db().collection("customers").document(customer_id).update(fields)


# ---------------------------------------------------------------------------
# Consent subcollection
# ---------------------------------------------------------------------------


async def record_consent(
    customer_id: str,
    *,
    tos_accepted_at: str,
    tos_version: str,
    privacy_accepted_at: str,
    privacy_version: str,
    consent_source: str,
) -> None:
    """Write consent record to ``customers/{id}/consent/`` subcollection."""
    await (
        get_db()
        .collection("customers")
        .document(customer_id)
        .collection("consent")
        .document("latest")
        .set(
            {
                "tos_accepted_at": tos_accepted_at,
                "tos_version": tos_version,
                "privacy_accepted_at": privacy_accepted_at,
                "privacy_version": privacy_version,
                "consent_source": consent_source,
            }
        )
    )


# ---------------------------------------------------------------------------
# License keys
# ---------------------------------------------------------------------------


async def get_license_key(key_hash: str) -> dict[str, Any] | None:
    """Fetch license key doc by SHA-256 hash."""
    doc = await get_db().collection("license_keys").document(key_hash).get()
    return doc.to_dict() if doc.exists else None


async def create_license_key(key_hash: str, data: dict[str, Any]) -> None:
    """Create a license key document."""
    await get_db().collection("license_keys").document(key_hash).set(data)


async def update_license_key(key_hash: str, fields: dict[str, Any]) -> None:
    """Merge-update fields on a license key document."""
    await get_db().collection("license_keys").document(key_hash).update(fields)


async def delete_license_key(key_hash: str) -> None:
    """Delete a license key document."""
    await get_db().collection("license_keys").document(key_hash).delete()


async def find_license_key_by_customer(
    customer_id: str,
) -> tuple[str, dict[str, Any]] | None:
    """Find active license key for a customer.

    Returns ``(key_hash, data)`` or ``None``.
    """
    query = (
        get_db()
        .collection("license_keys")
        .where("customer_id", "==", customer_id)
        .where("status", "==", "active")
        .limit(1)
    )
    docs = [doc async for doc in query.stream()]
    if not docs:
        return None
    return docs[0].id, docs[0].to_dict()  # type: ignore[return-value]


# ---------------------------------------------------------------------------
# API keys
# ---------------------------------------------------------------------------


async def create_api_key(key_hash: str, data: dict[str, Any]) -> None:
    """Create an API key document."""
    await get_db().collection("api_keys").document(key_hash).set(data)


# ---------------------------------------------------------------------------
# Health checks
# ---------------------------------------------------------------------------


async def check_firestore_health() -> bool:
    """Return ``True`` if Firestore is reachable."""
    try:
        # List one collection to prove connectivity
        cols = [c async for c in get_db().collections()]  # noqa: C416
        _ = cols  # discard, we just need the round-trip
        return True
    except Exception:
        _log.exception("Firestore health check failed")
        return False
