import { upsertGalleryImagesByUrls } from '../../lib/gallery.js'
import { prisma } from '../../lib/prisma.js'
import {
  formatFileTooLargeMessage,
  getProductImageMaxFileBytes,
  isMultipartFileTooLargeError,
} from '../../lib/upload-limits.js'
import { persistMultipartImages } from '../../lib/upload-images.js'

const CREATE_PRODUCT_SCHEMA = {
  body: {
    type: 'object',
    required: ['title', 'priceCents', 'quantity', 'categoryId'],
    properties: {
      title: { type: 'string', minLength: 1 },
      slug: { type: 'string' },
      categoryId: { type: 'string', minLength: 1 },
      priceCents: { type: 'number', minimum: 0 },
      quantity: { type: 'number', minimum: 0 },
      shortDescription: { type: 'string', nullable: true },
      description: { type: 'string', nullable: true },
      materials: { anyOf: [{ type: 'array', items: { type: 'string' } }, { type: 'string' }] },
      imageUrl: { type: 'string', nullable: true },
      imageUrls: { type: 'array', items: { type: 'string' } },
      published: { type: 'boolean' },
    },
  },
}

const PATCH_PRODUCT_SCHEMA = {
  body: {
    type: 'object',
    properties: {
      title: { type: 'string', minLength: 1 },
      slug: { type: 'string' },
      categoryId: { type: 'string', minLength: 1 },
      priceCents: { type: 'number', minimum: 0 },
      quantity: { type: 'number', minimum: 0 },
      shortDescription: { type: 'string', nullable: true },
      description: { type: 'string', nullable: true },
      materials: { anyOf: [{ type: 'array', items: { type: 'string' } }, { type: 'string' }] },
      imageUrl: { type: 'string', nullable: true },
      imageUrls: { type: 'array', items: { type: 'string' } },
      published: { type: 'boolean' },
    },
  },
}

export async function registerAdminProductRoutes(fastify) {
  fastify.get(
    '/api/admin/products',
    { preHandler: [fastify.verifyAdmin] },
    async (request) => {
      const items = await prisma.product.findMany({
        include: { category: true, images: { orderBy: { sort: 'asc' } } },
        orderBy: { updatedAt: 'desc' },
      })
      return items.map((p) => request.server.mapProductForApi(p))
    },
  )

  fastify.post(
    '/api/admin/uploads',
    { preHandler: [fastify.verifyAdmin] },
    async (request, reply) => {
      try {
        const urls = await persistMultipartImages(request, {
          maxFiles: 10,
          maxFileBytes: getProductImageMaxFileBytes(),
          eager: true,
        })
        await upsertGalleryImagesByUrls(urls)
        return { urls }
      } 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(getProductImageMaxFileBytes())
          statusCode = 413
        }
        return reply.code(statusCode).send({ error: message })
      }
    },
  )

  fastify.post(
    '/api/admin/products',
    { preHandler: [fastify.verifyAdmin], schema: CREATE_PRODUCT_SCHEMA },
    async (request, reply) => {
      const body = request.body ?? {}
      const title = String(body.title ?? '').trim()
      if (!title) {
        reply.code(400).send({ error: 'Укажите название' })
        return
      }
      const slug = String(body.slug ?? '').trim() || request.server.slugify(title) || `item-${Date.now()}`
      const categoryId = String(body.categoryId ?? '').trim()
      if (!categoryId) {
        reply.code(400).send({ error: 'Укажите категорию' })
        return
      }
      const cat = await prisma.category.findUnique({ where: { id: categoryId } })
      if (!cat) {
        reply.code(400).send({ error: 'Категория не найдена' })
        return
      }
      const priceCents = Number(body.priceCents)
      if (!Number.isFinite(priceCents) || priceCents <= 0) {
        reply.code(400).send({ error: 'Цена должна быть больше 0' })
        return
      }
      if (priceCents > 10_000_00) {
        reply.code(400).send({ error: 'Цена не может превышать 10 000 ₽' })
        return
      }
      const exists = await prisma.product.findUnique({ where: { slug } })
      if (exists) {
        reply.code(409).send({ error: 'Такой slug уже занят' })
        return
      }

      const n = Number(body.quantity)
      if (!Number.isInteger(n) || n < 0 || n > 10) {
        reply.code(400).send({ error: 'Количество — целое число от 0 до 10' })
        return
      }
      const quantity = n

      const product = await prisma.product.create({
        data: {
          title,
          slug,
          shortDescription: body.shortDescription ? String(body.shortDescription) : null,
          description: body.description ? String(body.description) : null,
          quantity,
          materials: JSON.stringify(request.server.parseMaterialsInput(body.materials)),
          priceCents: Math.round(priceCents),
          imageUrl: body.imageUrl ? String(body.imageUrl) : null,
          published: Boolean(body.published),
          categoryId,
          images: Array.isArray(body.imageUrls)
            ? {
                create: body.imageUrls
                  .map((u) => String(u || '').trim())
                  .filter(Boolean)
                  .slice(0, 10)
                  .map((u, idx) => ({ url: u, sort: idx })),
              }
            : undefined,
        },
        include: { category: true, images: { orderBy: { sort: 'asc' } } },
      })
      reply.code(201).send(request.server.mapProductForApi(product))
    },
  )

  fastify.patch(
    '/api/admin/products/:id',
    { preHandler: [fastify.verifyAdmin], schema: PATCH_PRODUCT_SCHEMA },
    async (request, reply) => {
      const { id } = request.params
      const body = request.body ?? {}
      const existing = await prisma.product.findUnique({ where: { id } })
      if (!existing) {
        reply.code(404).send({ error: 'Товар не найден' })
        return
      }
      const data = {}
      if (body.title !== undefined) data.title = String(body.title).trim()
      if (body.slug !== undefined) {
        const s = String(body.slug).trim()
        if (s && s !== existing.slug) {
          const clash = await prisma.product.findFirst({ where: { slug: s, NOT: { id } } })
          if (clash) {
            reply.code(409).send({ error: 'Такой slug уже занят' })
            return
          }
          data.slug = s
        }
      }
      if (body.shortDescription !== undefined) {
        data.shortDescription = body.shortDescription ? String(body.shortDescription) : null
      }
      if (body.description !== undefined) {
        data.description = body.description ? String(body.description) : null
      }
      if (body.quantity !== undefined) {
        const n = Number(body.quantity)
        if (!Number.isInteger(n) || n < 0 || n > 10) {
          reply.code(400).send({ error: 'Количество — целое число от 0 до 10' })
          return
        }
        data.quantity = n
      }
      if (body.materials !== undefined) {
        data.materials = JSON.stringify(request.server.parseMaterialsInput(body.materials))
      }
      if (body.priceCents !== undefined) {
        const p = Number(body.priceCents)
        if (!Number.isFinite(p) || p <= 0) {
          reply.code(400).send({ error: 'Цена должна быть больше 0' })
          return
        }
        if (p > 10_000_00) {
          reply.code(400).send({ error: 'Цена не может превышать 10 000 ₽' })
          return
        }
        data.priceCents = Math.round(p)
      }
      if (body.imageUrl !== undefined) {
        data.imageUrl = body.imageUrl ? String(body.imageUrl) : null
      }
      if (body.published !== undefined) data.published = Boolean(body.published)
      if (body.categoryId !== undefined) {
        const cid = String(body.categoryId).trim()
        if (!cid) {
          reply.code(400).send({ error: 'Укажите категорию' })
          return
        }
        const cat = await prisma.category.findUnique({ where: { id: cid } })
        if (!cat) {
          reply.code(400).send({ error: 'Категория не найдена' })
          return
        }
        data.categoryId = cid
      }

      const imagesUpdate =
        body.imageUrls !== undefined
          ? {
              deleteMany: {},
              create: Array.isArray(body.imageUrls)
                ? body.imageUrls
                    .map((u) => String(u || '').trim())
                    .filter(Boolean)
                    .slice(0, 10)
                    .map((u, idx) => ({ url: u, sort: idx }))
                : [],
            }
          : undefined

      const product = await prisma.product.update({
        where: { id },
        data: { ...data, images: imagesUpdate },
        include: { category: true, images: { orderBy: { sort: 'asc' } } },
      })
      return request.server.mapProductForApi(product)
    },
  )

  fastify.delete(
    '/api/admin/products/:id',
    { preHandler: [fastify.verifyAdmin] },
    async (request, reply) => {
      const { id } = request.params
      try {
        await prisma.product.delete({ where: { id } })
        reply.code(204).send()
      } catch {
        reply.code(404).send({ error: 'Товар не найден' })
      }
    },
  )
}
