import { isDeliveryCarrier } from '../lib/delivery-carrier.js'
import { prisma } from '../lib/prisma.js'

export async function registerUserOrderRoutes(fastify) {
  // ---- Создание заказа (checkout) ----

  fastify.post(
    '/api/me/orders',
    { preHandler: [fastify.authenticate] },
    async (request, reply) => {
      const userId = request.user.sub
      const deliveryTypeRaw = request.body?.deliveryType
      const deliveryType =
        deliveryTypeRaw === undefined || deliveryTypeRaw === null || deliveryTypeRaw === ''
          ? 'delivery'
          : String(deliveryTypeRaw).trim()

      const addressId = String(request.body?.addressId || '').trim()
      const commentRaw = request.body?.comment
      const comment = commentRaw === null || commentRaw === undefined ? null : String(commentRaw).trim()

      const paymentMethodRaw = request.body?.paymentMethod
      const paymentMethod =
        paymentMethodRaw === undefined || paymentMethodRaw === null || paymentMethodRaw === ''
          ? 'online'
          : String(paymentMethodRaw).trim()
      if (paymentMethod !== 'online' && paymentMethod !== 'on_pickup') {
        return reply.code(400).send({ error: 'paymentMethod должен быть online | on_pickup' })
      }

      if (deliveryType !== 'delivery' && deliveryType !== 'pickup') {
        return reply.code(400).send({ error: 'deliveryType должен быть delivery | pickup' })
      }

      const carrierRaw = request.body?.deliveryCarrier
      let deliveryCarrier = null
      if (deliveryType === 'delivery') {
        const carrierStr =
          carrierRaw === undefined || carrierRaw === null || carrierRaw === ''
            ? ''
            : String(carrierRaw).trim()
        if (!isDeliveryCarrier(carrierStr)) {
          return reply
            .code(400)
            .send({
              error:
                'deliveryCarrier обязателен для доставки: RUSSIAN_POST | OZON_PVZ | YANDEX_PVZ | FIVE_POST',
            })
        }
        deliveryCarrier = carrierStr
      }

      if (paymentMethod === 'on_pickup' && deliveryType !== 'pickup') {
        return reply.code(400).send({ error: 'Оплата при получении доступна только для самовывоза' })
      }

      let address = null
      if (deliveryType === 'delivery') {
        if (!addressId) return reply.code(400).send({ error: 'Выберите адрес доставки' })
        address = await prisma.shippingAddress.findFirst({ where: { id: addressId, userId } })
        if (!address) return reply.code(404).send({ error: 'Адрес не найден' })
      }

      const cartItems = await prisma.cartItem.findMany({
        where: { userId },
        include: { product: true },
      })
      if (cartItems.length === 0) return reply.code(400).send({ error: 'Корзина пуста' })

      for (const ci of cartItems) {
        const available = ci.product.inStock ? ci.product.quantity : 1
        if (ci.qty > available) {
          return reply.code(409).send({ error: `Недостаточно товара: "${ci.product.title}". Доступно: ${available} шт.` })
        }
      }

      const itemsPayload = cartItems.map((ci) => ({
        productId: ci.productId,
        qty: ci.qty,
        titleSnapshot: ci.product.title,
        priceCentsSnapshot: ci.product.priceCents,
      }))

      const itemsSubtotalCents = itemsPayload.reduce((sum, i) => sum + i.priceCentsSnapshot * i.qty, 0)
      const deliveryFeeCents = deliveryType === 'delivery' ? 50000 : 0
      const totalCents = itemsSubtotalCents + deliveryFeeCents

      const addressSnapshotJson =
        deliveryType === 'pickup'
          ? JSON.stringify({ deliveryType: 'pickup' })
          : JSON.stringify({
              deliveryType: 'delivery',
              id: address.id,
              label: address.label,
              recipientName: address.recipientName,
              recipientPhone: address.recipientPhone,
              addressLine: address.addressLine,
              comment: address.comment,
              lat: address.lat,
              lng: address.lng,
            })

      let initialStatus = 'PENDING_PAYMENT'
      if (paymentMethod === 'on_pickup') initialStatus = 'IN_PROGRESS'
      else if (deliveryType === 'delivery') initialStatus = 'DELIVERY_FEE_ADJUSTMENT'

      let created
      try {
        created = await prisma.$transaction(async (tx) => {
          for (const ci of cartItems) {
            if (!ci.product.inStock) continue

            const res = await tx.product.updateMany({
              where: { id: ci.productId, quantity: { gte: ci.qty } },
              data: { quantity: { decrement: ci.qty } },
            })
            if (res.count !== 1) {
              throw new Error(`Недостаточно товара: "${ci.product.title}"`)
            }

          }

          const order = await tx.order.create({
            data: {
              userId,
              status: initialStatus,
              deliveryType,
              deliveryCarrier,
              paymentMethod,
              itemsSubtotalCents,
              deliveryFeeCents,
              totalCents,
              currency: 'RUB',
              addressSnapshotJson,
              comment: comment && comment.length ? comment : null,
              items: {
                create: itemsPayload.map((i) => ({
                  productId: i.productId,
                  qty: i.qty,
                  titleSnapshot: i.titleSnapshot,
                  priceCentsSnapshot: i.priceCentsSnapshot,
                })),
              },
            },
          })
          await tx.cartItem.deleteMany({ where: { userId } })
          return order
        })
      } catch (e) {
        return reply.code(409).send({ error: (e instanceof Error && e.message) || 'Недостаточно товара' })
      }

      return reply.code(201).send({ orderId: created.id })
    },
  )

  fastify.get(
    '/api/me/orders',
    { preHandler: [fastify.authenticate] },
    async (request) => {
      const userId = request.user.sub
      const orders = await prisma.order.findMany({
        where: { userId },
        include: { items: true },
        orderBy: { createdAt: 'desc' },
      })
      return {
        items: orders.map((o) => ({
          id: o.id,
          status: o.status,
          totalCents: o.totalCents,
          currency: o.currency,
          createdAt: o.createdAt,
          updatedAt: o.updatedAt,
          itemsCount: o.items.reduce((s, i) => s + i.qty, 0),
        })),
      }
    },
  )

  fastify.get(
    '/api/me/orders/:id',
    { preHandler: [fastify.authenticate] },
    async (request, reply) => {
      const userId = request.user.sub
      const { id } = request.params
      const order = await prisma.order.findFirst({
        where: { id, userId },
        include: { items: true, messages: { orderBy: { createdAt: 'asc' } } },
      })
      if (!order) return reply.code(404).send({ error: 'Заказ не найден' })
      return { item: order }
    },
  )

  fastify.get(
    '/api/me/orders/:id/review-eligibility',
    { preHandler: [fastify.authenticate] },
    async (request, reply) => {
      const userId = request.user.sub
      const { id } = request.params
      const order = await prisma.order.findFirst({ where: { id, userId }, include: { items: true } })
      if (!order) return reply.code(404).send({ error: 'Заказ не найден' })
      if (order.status !== 'DONE') {
        return { canReview: false, items: [] }
      }

      const uniq = new Map()
      for (const it of order.items) {
        if (!uniq.has(it.productId)) {
          uniq.set(it.productId, { productId: it.productId, title: it.titleSnapshot })
        }
      }
      const productIds = [...uniq.keys()]
      const existing = await prisma.review.findMany({
        where: { userId, productId: { in: productIds } },
        select: { productId: true },
      })
      const reviewed = new Set(existing.map((r) => r.productId))
      return {
        canReview: true,
        items: [...uniq.values()].map((x) => ({
          ...x,
          hasReview: reviewed.has(x.productId),
        })),
      }
    },
  )

  fastify.post(
    '/api/me/orders/:id/confirm-received',
    { preHandler: [fastify.authenticate] },
    async (request, reply) => {
      const userId = request.user.sub
      const { id } = request.params
      const order = await prisma.order.findFirst({ where: { id, userId } })
      if (!order) return reply.code(404).send({ error: 'Заказ не найден' })

      const okDelivery = order.deliveryType === 'delivery' && order.status === 'SHIPPED'
      const okPickup = order.deliveryType === 'pickup' && order.status === 'READY_FOR_PICKUP'
      if (!okDelivery && !okPickup) {
        return reply.code(409).send({ error: 'Сейчас нельзя подтвердить получение заказа' })
      }

      await prisma.order.update({ where: { id }, data: { status: 'DONE' } })
      return { ok: true, status: 'DONE' }
    },
  )
}
