import { NOTIFICATION_EVENTS } from '../../../shared/constants/notification-events.js'
import { asyncHandler } from '../lib/async-handler.js'
import { findUserOrder } from '../lib/find-user-order.js'
import { prisma } from '../lib/prisma.js'
import { createPayment, buildReceipt, getPayment } from '../lib/yookassa.js'

export async function registerUserPaymentRoutes(fastify) {
  fastify.post(
    '/api/me/orders/:id/pay',
    { preHandler: [fastify.authenticate] },
    asyncHandler(async (request, reply) => {
      const userId = request.user.sub
      const userEmail = request.user.email

      if (!userEmail) {
        return reply.code(422).send({ error: 'Для онлайн-оплаты необходим email в профиле' })
      }

      const { id } = request.params

      const order = await findUserOrder(prisma, id, userId, { items: true })

      if (order.paymentMethod === 'on_pickup') {
        return reply.code(409).send({
          error: 'Для этого заказа оплата при получении — онлайн-оплата недоступна',
        })
      }

      if (order.status !== 'PENDING_PAYMENT') {
        return reply.code(409).send({ error: 'Сейчас нельзя выполнить оплату для этого заказа' })
      }

      if (!order.deliveryFeeLocked) {
        return reply.code(409).send({
          error: 'Стоимость доставки ещё утверждается — оплата станет доступна позже',
        })
      }

      const existingPayment = await prisma.payment.findFirst({
        where: {
          orderId: id,
          status: { in: ['pending', 'waiting_for_capture'] },
          OR: [{ expiresAt: null }, { expiresAt: { gt: new Date() } }],
        },
        orderBy: { createdAt: 'desc' },
      })

      if (existingPayment && existingPayment.confirmationUrl) {
        return { confirmationUrl: existingPayment.confirmationUrl }
      }

      const idempotencyKey = `${id}-${Date.now()}`
      const clientUrl = (process.env.CLIENT_PUBLIC_URL || 'http://127.0.0.1:5173').replace(/\/$/, '')
      const returnUrl = `${clientUrl}/me/orders/${id}?paid=1`
      const clientIp = request.ip

      const amount = {
        value: (order.totalCents / 100).toFixed(2),
        currency: order.currency,
      }

      const receipt = buildReceipt({
        orderItems: order.items,
        deliveryFeeCents: order.deliveryFeeCents,
        userEmail: userEmail,
      })

      let result
      try {
        result = await createPayment({
          amount,
          description: `Оплата заказа №${order.id.slice(-6)}`,
          receipt,
          confirmation: { type: 'redirect', return_url: returnUrl },
          metadata: { orderId: order.id },
          idempotencyKey,
          clientIp,
        })
      } catch (err) {
        request.log.error({ err, orderId: id }, 'YooKassa createPayment failed')
        return reply.code(502).send({
          error: 'Не удалось создать платёж. Платёжный сервис временно недоступен.',
        })
      }

      await prisma.payment.create({
        data: {
          orderId: order.id,
          yookassaPaymentId: result.paymentId,
          status: result.status,
          amountCents: order.totalCents,
          currency: order.currency,
          confirmationUrl: result.confirmationUrl,
          expiresAt: result.expiresAt ? new Date(result.expiresAt) : null,
        },
      })

      return { confirmationUrl: result.confirmationUrl }
    }),
  )

  fastify.get(
    '/api/me/orders/:orderId/payment',
    { preHandler: [fastify.authenticate] },
    asyncHandler(async (request, reply) => {
      const userId = request.user.sub
      const { orderId } = request.params

      const order = await findUserOrder(prisma, orderId, userId)

      const payment = await prisma.payment.findFirst({
        where: { orderId },
        orderBy: { createdAt: 'desc' },
      })
      if (!payment) {
        return { status: null, paid: false }
      }

      if (payment.status === 'succeeded' || payment.status === 'canceled') {
        return { status: payment.status, paid: payment.status === 'succeeded' }
      }

      try {
        const ykPayment = await getPayment(payment.yookassaPaymentId)

        if (ykPayment.status !== payment.status) {
          await prisma.payment.update({
            where: { id: payment.id },
            data: { status: ykPayment.status },
          })

          if (ykPayment.status === 'succeeded' && order.status === 'PENDING_PAYMENT') {
            const updated = await prisma.order.updateMany({
              where: { id: orderId, status: 'PENDING_PAYMENT' },
              data: { status: 'PAID' },
            })
            if (updated.count > 0) {
              request.server.eventBus.emit(NOTIFICATION_EVENTS.PAYMENT_STATUS_CHANGED, {
                orderId,
                userId: order.userId,
                paymentStatus: 'paid',
              })
            }
          }
        }

        return { status: ykPayment.status, paid: ykPayment.paid }
      } catch (err) {
        request.log.error({ err }, '[user-payments] Operation failed')
        return { status: payment.status, paid: payment.status === 'succeeded' }
      }
    }),
  )
}
