from __future__ import annotations

import logging
from typing import Any, Optional

from aiogram import Bot
from sqlalchemy.ext.asyncio import AsyncSession

from bot.services.user_email_notifications import send_user_notification_email
from db.dal import payment_dal, user_dal
from db.models import Payment

from .common import make_translator


def coerce_payment_db_id(order_id_raw: Any) -> Optional[int]:
    """Pull a numeric DB id out of a webhook's ``orderId``/``order_id`` field."""
    if isinstance(order_id_raw, int):
        return order_id_raw
    if isinstance(order_id_raw, str) and order_id_raw.isdigit():
        return int(order_id_raw)
    return None


async def lookup_payment_by_order_or_provider_id(
    session: AsyncSession,
    *,
    order_id_raw: Any = None,
    provider_payment_id: Optional[str] = None,
) -> Optional[Payment]:
    """Find a payment by DB id first, fall back to provider id.

    Returns ``None`` so callers stay in charge of the not-found response.
    """
    payment_db_id = coerce_payment_db_id(order_id_raw)
    payment: Optional[Payment] = None
    if payment_db_id is not None:
        payment = await payment_dal.get_payment_by_db_id(session, payment_db_id)
    if not payment and provider_payment_id:
        payment = await payment_dal.get_payment_by_provider_payment_id(session, provider_payment_id)
    return payment


async def notify_user_payment_failed(
    *,
    bot: Bot,
    settings: Any,
    i18n: Any,
    session: AsyncSession,
    payment: Payment,
    message_key: str = "payment_failed",
) -> None:
    """Send the localized ``payment_failed`` text to the user; never raises."""
    db_user = payment.user or await user_dal.get_user_by_id(session, payment.user_id)
    language = (
        db_user.language_code if db_user and db_user.language_code else settings.DEFAULT_LANGUAGE
    )
    translator = make_translator(i18n, language)
    message_text = translator(message_key)
    try:
        await bot.send_message(payment.user_id, message_text)
    except Exception:
        logging.exception(
            "Webhook helper: failed to notify user %s about %s.",
            payment.user_id,
            message_key,
        )
    if db_user:
        await send_user_notification_email(
            settings=settings,
            i18n=i18n,
            user=db_user,
            subject_key="email_payment_failed_subject",
            message_text=message_text,
            dashboard_url=(getattr(settings, "SUBSCRIPTION_MINI_APP_URL", "") or None),
        )
