from datetime import timedelta

from django.conf import settings
from django.db.models import Count, Max, Min
from django.utils import timezone

from api.models import IntegrationOutbox, IntegrationPublisherState, IntegrationTransportCursor
from api.services.integration.outbox import integration_source_scope


def phase1_readiness(*, require_enabled=False) -> dict:
    config = settings.RESOURCE_BOOKING_INTEGRATION
    source_scope = integration_source_scope()
    errors = []
    if not config.get("CAPTURE_ENABLED"):
        errors.append("capture is disabled")
    if config.get("PHASE") != "phase1":
        errors.append("phase must equal phase1")
    if config.get("REVERSE_DELIVERY_ENABLED"):
        errors.append("Phase 2 reverse delivery is enabled")
    if config.get("SCHEMA_VERSION") != "2":
        errors.append("canonical schema version must equal 2")
    if require_enabled or config.get("PUBLISH_ENABLED"):
        if not config.get("PUBLISH_ENABLED"):
            errors.append("publishing is disabled")
        if not config.get("ACTIVATION_APPROVED"):
            errors.append("activation approval is not attested")
        if config.get("TRANSPORT") != "kafka":
            errors.append("transport must equal kafka")
        if not config.get("KAFKA_TOPIC"):
            errors.append("Kafka topic is missing")
        if not config.get("KAFKA_BOOTSTRAP_SERVERS"):
            errors.append("Kafka bootstrap servers are missing")
        if not config.get("SNAPSHOT_SERVICE_TOKEN"):
            errors.append("snapshot service token is missing")
        if config.get("PUBLISHER_CONCURRENCY") != 1:
            errors.append("publisher concurrency must equal 1")

    outbox = IntegrationOutbox.objects.filter(source_scope=source_scope)
    aggregate = outbox.aggregate(
        count=Count("transport_sequence", distinct=True),
        minimum=Min("transport_sequence"),
        maximum=Max("transport_sequence"),
    )
    unfinalized = outbox.filter(transaction_finalized=False).count()
    dead_letters = outbox.filter(status=IntegrationOutbox.Status.DEAD_LETTER).count()
    if unfinalized:
        errors.append(f"{unfinalized} transport event(s) are not finalized")
    if dead_letters:
        errors.append(f"{dead_letters} dead-letter event(s) block ordered publication")
    if aggregate["count"] and (
        aggregate["minimum"] != 1
        or aggregate["maximum"] - aggregate["minimum"] + 1 != aggregate["count"]
    ):
        errors.append("transport sequence contains a gap")

    cursor = IntegrationTransportCursor.objects.filter(source_scope=source_scope).first()
    cursor_sequence = cursor.last_sequence if cursor else 0
    if cursor_sequence != (aggregate["maximum"] or 0):
        errors.append("transport cursor does not match the committed outbox high-water mark")

    publisher = IntegrationPublisherState.objects.filter(source_scope=source_scope).first()
    publisher_live = False
    if publisher and publisher.heartbeat_at:
        publisher_live = publisher.heartbeat_at >= timezone.now() - timedelta(
            seconds=config["PUBLISHER_HEARTBEAT_TIMEOUT_SECONDS"]
        )
    # Preflight is intentionally restart-safe: a stale heartbeat from a crashed
    # prior process must not prevent the supervisor from starting its replacement.
    # The post-start liveness probe separately requires publisher_live=True.

    return {
        "ready": not errors,
        "errors": errors,
        "phase": config.get("PHASE"),
        "reverse_delivery_enabled": bool(config.get("REVERSE_DELIVERY_ENABLED")),
        "capture_enabled": bool(config.get("CAPTURE_ENABLED")),
        "publish_enabled": bool(config.get("PUBLISH_ENABLED")),
        "activation_approved": bool(config.get("ACTIVATION_APPROVED")),
        "source_scope": source_scope,
        "schema_version": config.get("SCHEMA_VERSION"),
        "transport": config.get("TRANSPORT"),
        "topic_configured": bool(config.get("KAFKA_TOPIC")),
        "snapshot_auth_configured": bool(config.get("SNAPSHOT_SERVICE_TOKEN")),
        "outbox_count": aggregate["count"],
        "transport_watermark": aggregate["maximum"] or 0,
        "dead_letter_count": dead_letters,
        "publisher_live": publisher_live,
        "publisher_status": publisher.status if publisher else "not_started",
        "publisher_last_sequence": publisher.last_published_sequence if publisher else 0,
    }
