"""Worker task: complete pre-registration after Stripe checkout.

Fired by the billing webhook when checkout.session.completed contains a
pending_registration_id — i.e. the user paid before verifying their email.

Steps:
  1. Look up PendingRegistration; skip if already paid (idempotent).
  2. Mark paid + store stripe_customer_id and stripe_subscription_id.
  3. Send magic link email so the user can verify their email and land on the dashboard.
"""
from __future__ import annotations

from datetime import datetime, timezone
from typing import Optional
from uuid import UUID

import structlog

logger = structlog.get_logger()


async def complete_pre_registration(
    ctx: dict,
    *,
    pending_registration_id: str,
    stripe_customer_id: str,
    stripe_subscription_id: Optional[str] = None,
) -> dict:
    """Mark PendingRegistration as paid and send the magic link email."""
    from src.config import get_settings
    from src.core.database import async_session_factory
    from src.domain.auth.repository import (
        MagicLinkRepository,
        PendingRegistrationRepository,
        SessionRepository,
        UserRepository,
    )
    from src.domain.auth.mfa_repository import TotpSecretRepository
    from src.domain.auth.service import AuthService
    from src.integrations.email_provider import email_transport_configured, get_email_provider

    settings = get_settings()
    db_factory = ctx.get("db_factory", async_session_factory)

    try:
        pending_id = UUID(pending_registration_id)
    except (ValueError, AttributeError):
        logger.error("complete_pre_registration_invalid_id", pending_registration_id=pending_registration_id)
        return {"status": "invalid_id"}

    async with db_factory() as db:
        pending_repo = PendingRegistrationRepository(db)
        pending = await pending_repo.get_by_id(pending_id)

        if not pending:
            logger.warning(
                "complete_pre_registration_not_found",
                pending_registration_id=pending_registration_id,
            )
            return {"status": "not_found"}

        if pending.paid_at:
            logger.info(
                "complete_pre_registration_already_paid",
                pending_registration_id=pending_registration_id,
            )
            return {"status": "already_processed"}

        now = datetime.now(timezone.utc)
        await pending_repo.mark_paid(
            pending_id,
            paid_at=now,
            stripe_subscription_id=stripe_subscription_id,
        )
        # Ensure stripe_customer_id is stored (may not have been set if checkout was direct)
        if stripe_customer_id and not pending.stripe_customer_id:
            await pending_repo.update_checkout(
                pending_id,
                checkout_session_id=pending.checkout_session_id or "",
                checkout_expires_at=pending.checkout_expires_at or now,
                stripe_customer_id=stripe_customer_id,
            )
        await db.commit()

        email = pending.email

    # Send magic link email in a fresh session (after commit)
    async with db_factory() as db:
        user_repo = UserRepository(db)
        pending_repo = PendingRegistrationRepository(db)
        email_provider = None
        if email_transport_configured(settings):
            email_provider = get_email_provider()

        auth_svc = AuthService(
            user_repo=user_repo,
            session_repo=SessionRepository(db),
            magic_link_repo=MagicLinkRepository(db),
            totp_repo=TotpSecretRepository(db),
            email_provider=email_provider,
            pending_repo=pending_repo,
        )

        await auth_svc.request_magic_link(
            email,
            app_base_url=settings.app_url,
            allow_unknown_email=True,
            is_signup=True,
        )
        await db.commit()

    logger.info(
        "complete_pre_registration_done",
        email=email,
        pending_registration_id=pending_registration_id,
        stripe_customer_id=stripe_customer_id,
    )
    return {"status": "completed", "email": email}


async def scan_abandoned_pre_registrations(ctx: dict) -> dict:
    """Drain legacy scanner jobs without enqueueing signup recovery emails."""
    logger.info("scan_abandoned_pre_registrations_disabled")
    return {"status": "disabled", "queued": 0}


async def send_pre_registration_recovery_email(
    ctx: dict,
    *,
    pending_registration_id: str,
) -> dict:
    """Drain already-queued recovery jobs without sending an email.

    Keep this task registered so jobs queued before recovery was disabled can
    finish successfully, including retries from older workers.
    """
    logger.info("pre_registration_recovery_disabled")
    return {"status": "disabled"}
