"""CRUD операции для платежей SeverPay."""

from datetime import UTC, datetime

import structlog
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.database.models import SeverPayPayment


logger = structlog.get_logger(__name__)


async def create_severpay_payment(
    db: AsyncSession,
    *,
    user_id: int | None,
    order_id: str,
    amount_kopeks: int,
    currency: str = 'RUB',
    description: str | None = None,
    payment_url: str | None = None,
    payment_method: str | None = None,
    severpay_id: str | None = None,
    severpay_uid: str | None = None,
    expires_at: datetime | None = None,
    metadata_json: dict | None = None,
) -> SeverPayPayment:
    """Создает запись о платеже SeverPay."""
    payment = SeverPayPayment(
        user_id=user_id,
        order_id=order_id,
        amount_kopeks=amount_kopeks,
        currency=currency,
        description=description,
        payment_url=payment_url,
        payment_method=payment_method,
        severpay_id=severpay_id,
        severpay_uid=severpay_uid,
        expires_at=expires_at,
        metadata_json=metadata_json,
        status='pending',
        is_paid=False,
    )
    db.add(payment)
    await db.commit()
    await db.refresh(payment)
    logger.info('Создан платеж SeverPay', order_id=order_id, user_id=user_id)
    return payment


async def get_severpay_payment_by_order_id(db: AsyncSession, order_id: str) -> SeverPayPayment | None:
    """Получает платеж по order_id (internal)."""
    result = await db.execute(select(SeverPayPayment).where(SeverPayPayment.order_id == order_id))
    return result.scalar_one_or_none()


async def get_severpay_payment_by_severpay_id(db: AsyncSession, severpay_id: str) -> SeverPayPayment | None:
    """Получает платеж по ID от SeverPay."""
    result = await db.execute(select(SeverPayPayment).where(SeverPayPayment.severpay_id == severpay_id))
    return result.scalar_one_or_none()


async def get_severpay_payment_by_id(db: AsyncSession, payment_id: int) -> SeverPayPayment | None:
    """Получает платеж по ID."""
    result = await db.execute(select(SeverPayPayment).where(SeverPayPayment.id == payment_id))
    return result.scalar_one_or_none()


async def get_severpay_payment_by_id_for_update(db: AsyncSession, payment_id: int) -> SeverPayPayment | None:
    """Получает платеж по ID с блокировкой FOR UPDATE."""
    result = await db.execute(
        select(SeverPayPayment)
        .where(SeverPayPayment.id == payment_id)
        .with_for_update()
        .execution_options(populate_existing=True)
    )
    return result.scalar_one_or_none()


async def update_severpay_payment_status(
    db: AsyncSession,
    payment: SeverPayPayment,
    *,
    status: str,
    is_paid: bool | None = None,
    severpay_id: str | None = None,
    severpay_uid: str | None = None,
    payment_method: str | None = None,
    callback_payload: dict | None = None,
    transaction_id: int | None = None,
) -> SeverPayPayment:
    """Обновляет статус платежа."""
    payment.status = status
    payment.updated_at = datetime.now(UTC)

    if is_paid is not None:
        payment.is_paid = is_paid
        if is_paid:
            payment.paid_at = datetime.now(UTC)
    if severpay_id is not None:
        payment.severpay_id = severpay_id
    if severpay_uid is not None:
        payment.severpay_uid = severpay_uid
    if payment_method is not None:
        payment.payment_method = payment_method
    if callback_payload is not None:
        payment.callback_payload = callback_payload
    if transaction_id is not None:
        payment.transaction_id = transaction_id

    await db.commit()
    await db.refresh(payment)
    logger.info(
        'Обновлен статус платежа SeverPay',
        order_id=payment.order_id,
        status=status,
        is_paid=payment.is_paid,
    )
    return payment


async def get_pending_severpay_payments(db: AsyncSession, user_id: int) -> list[SeverPayPayment]:
    """Получает незавершенные платежи пользователя."""
    result = await db.execute(
        select(SeverPayPayment).where(
            SeverPayPayment.user_id == user_id,
            SeverPayPayment.status == 'pending',
            SeverPayPayment.is_paid == False,
        )
    )
    return list(result.scalars().all())


async def get_expired_pending_severpay_payments(
    db: AsyncSession,
) -> list[SeverPayPayment]:
    """Получает просроченные платежи в статусе pending."""
    now = datetime.now(UTC)
    result = await db.execute(
        select(SeverPayPayment).where(
            SeverPayPayment.status == 'pending',
            SeverPayPayment.is_paid == False,
            SeverPayPayment.expires_at < now,
        )
    )
    return list(result.scalars().all())


async def link_severpay_payment_to_transaction(
    db: AsyncSession,
    *,
    payment: SeverPayPayment,
    transaction_id: int,
) -> SeverPayPayment:
    """Связывает платеж с транзакцией."""
    payment.transaction_id = transaction_id
    payment.updated_at = datetime.now(UTC)
    await db.flush()
    await db.refresh(payment)
    return payment
