from __future__ import annotations

import logging
from typing import Optional

from aiohttp import web
from sqlalchemy.ext.asyncio import AsyncSession

from db.dal import payment_dal
from db.models import Payment

from .common import mark_payment_failed_creation, payment_failed, payment_link_response


async def finalize_webapp_link_payment(
    *,
    session: AsyncSession,
    payment: Payment,
    api_success: bool,
    payment_url: Optional[str],
    provider_payment_id: Optional[str] = None,
    new_status: Optional[str] = None,
    log_prefix: str,
) -> web.Response:
    """The trailing "persist id → return link or fail" used by every link-style webapp creator.

    Mirrors :func:`render_link_or_fail` but for the webapp HTTP context: instead
    of editing a Telegram message it returns either ``payment_link_response``
    or ``payment_failed``. Provider modules just call:

        payment = await create_webapp_payment_record(ctx, ...)
        success, data = await service.create_xxx(...)
        return await finalize_webapp_link_payment(
            session=ctx.session,
            payment=payment,
            api_success=success,
            payment_url=first_value(data, "url", "payment_url"),
            provider_payment_id=first_value(data, "id"),
            log_prefix="Wata",
        )
    """
    if api_success and provider_payment_id:
        try:
            await payment_dal.update_provider_payment_and_status(
                session,
                payment.payment_id,
                str(provider_payment_id),
                new_status or payment.status,
            )
            await session.commit()
        except Exception:
            await session.rollback()
            logging.exception(
                "%s: failed to persist provider payment id for payment %s.",
                log_prefix,
                payment.payment_id,
            )

    if not payment_url:
        try:
            await mark_payment_failed_creation(session, payment.payment_id)
        except Exception:
            await session.rollback()
            logging.exception(
                "%s: failed to mark payment %s as failed_creation.",
                log_prefix,
                payment.payment_id,
            )
        return payment_failed()

    return payment_link_response(payment_url=payment_url, payment_id=payment.payment_id)
