import { publicReviewAuthorDisplay } from '../../lib/review-display.js'
import { prisma } from '../../lib/prisma.js'
import {
  formatFileTooLargeMessage,
  getOtherUploadMaxFileBytes,
  isMultipartFileTooLargeError,
} from '../../lib/upload-limits.js'
import { persistMultipartImages } from '../../lib/upload-images.js'

export async function registerPublicReviewRoutes(fastify) {
  fastify.post(
    '/api/reviews/upload-image',
    { preHandler: [fastify.authenticate] },
    async (request, reply) => {
      try {
        const urls = await persistMultipartImages(request, {
          maxFiles: 1,
          maxFileBytes: getOtherUploadMaxFileBytes(),
          subdir: 'reviews',
        })
        if (urls.length !== 1) return reply.code(400).send({ error: 'Нужно прикрепить 1 изображение' })
        return { url: urls[0] }
      } catch (error) {
        let message = error instanceof Error ? error.message : 'Не удалось загрузить изображение'
        let statusCode =
          error && typeof error === 'object' && 'statusCode' in error && Number.isInteger(error.statusCode)
            ? Number(error.statusCode)
            : 400
        if (isMultipartFileTooLargeError(error)) {
          message = formatFileTooLargeMessage(getOtherUploadMaxFileBytes())
          statusCode = 413
        }
        return reply.code(statusCode).send({ error: message })
      }
    },
  )

  fastify.get('/api/reviews/latest', async (request, reply) => {
    const limitRaw = request.query?.limit
    const limitParsed = typeof limitRaw === 'string' ? Number(limitRaw) : Number(limitRaw)
    const parsed = Number.isFinite(limitParsed) && limitParsed > 0 ? Math.floor(limitParsed) : 5
    const take = Math.min(parsed, 5)

    const rows = await prisma.review.findMany({
      where: { status: 'approved', product: { published: true } },
      include: {
        user: { select: { email: true, name: true } },
        product: { select: { id: true, title: true } },
      },
      orderBy: { createdAt: 'desc' },
      take,
    })

    const items = rows.map((r) => ({
      id: r.id,
      rating: r.rating,
      text: r.text,
      imageUrl: r.imageUrl,
      createdAt: r.createdAt,
      authorDisplay: publicReviewAuthorDisplay(r.user),
      productId: r.productId,
      productTitle: r.product?.title ?? '',
    }))

    return { items }
  })

  fastify.get('/api/products/:id/reviews', async (request, reply) => {
    const { id } = request.params

    const pageRaw = request.query?.page
    const pageParsed = typeof pageRaw === 'string' ? Number(pageRaw) : Number(pageRaw)
    const page = Number.isFinite(pageParsed) && pageParsed > 0 ? Math.floor(pageParsed) : 1

    const pageSizeRaw = request.query?.pageSize
    const pageSizeParsed = typeof pageSizeRaw === 'string' ? Number(pageSizeRaw) : Number(pageSizeRaw)
    const pageSize = Number.isFinite(pageSizeParsed) && pageSizeParsed > 0 ? Math.floor(pageSizeParsed) : 10
    if (pageSize > 50) return reply.code(400).send({ error: 'pageSize должен быть ≤ 50' })

    const product = await prisma.product.findFirst({ where: { id, published: true } })
    if (!product) return reply.code(404).send({ error: 'Товар не найден' })

    const where = { productId: id, status: 'approved' }
    const total = await prisma.review.count({ where })
    const rawItems = await prisma.review.findMany({
      where,
      include: { user: { select: { email: true, name: true } } },
      orderBy: { createdAt: 'desc' },
      skip: (page - 1) * pageSize,
      take: pageSize,
    })

    const items = rawItems.map((r) => ({
      id: r.id,
      rating: r.rating,
      text: r.text,
      imageUrl: r.imageUrl,
      createdAt: r.createdAt,
      authorDisplay: publicReviewAuthorDisplay(r.user),
    }))

    return { items, total, page, pageSize }
  })

  fastify.post(
    '/api/products/:id/reviews',
    { preHandler: [fastify.authenticate] },
    async (request, reply) => {
      const userId = request.user.sub
      const { id: productId } = request.params

      const product = await prisma.product.findFirst({ where: { id: productId, published: true } })
      if (!product) return reply.code(404).send({ error: 'Товар не найден' })

      const rating = Number(request.body?.rating)
      if (!Number.isFinite(rating) || rating < 1 || rating > 5) {
        return reply.code(400).send({ error: 'rating должен быть от 1 до 5' })
      }
      const textRaw = request.body?.text
      const text = textRaw === null || textRaw === undefined ? null : String(textRaw).trim()
      if (text !== null && text.length > 1000) return reply.code(400).send({ error: 'Отзыв слишком длинный' })
      const imageUrlRaw = request.body?.imageUrl
      const imageUrl = imageUrlRaw === null || imageUrlRaw === undefined ? null : String(imageUrlRaw).trim()
      if (imageUrl !== null && imageUrl.length > 300) return reply.code(400).send({ error: 'Ссылка на фото слишком длинная' })
      if (imageUrl !== null && imageUrl.length > 0 && !imageUrl.startsWith('/uploads/')) {
        return reply.code(400).send({ error: 'Некорректная ссылка на изображение' })
      }

      try {
        const created = await prisma.review.create({
          data: {
            productId,
            userId,
            rating: Math.floor(rating),
            text: text && text.length ? text : null,
            imageUrl: imageUrl && imageUrl.length ? imageUrl : null,
            status: 'pending',
          },
        })
        return reply.code(201).send({ item: created })
      } catch {
        return reply.code(409).send({ error: 'Вы уже оставляли отзыв на этот товар' })
      }
    },
  )
}

