import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import { getSpotDetail } from '@/lib/spots'
import { prisma } from '@/lib/prisma'
import DOMPurify from 'isomorphic-dompurify'
import { writeFile, mkdir } from 'fs/promises'
import { uploadDiskPath, uploadUrlPath } from '@/lib/upload-path'

export async function GET(_req: NextRequest, { params }: { params: { id: string } }) {
  const spot = await getSpotDetail(params.id)
  if (!spot) return NextResponse.json({ error: 'Spot não encontrado' }, { status: 404 })
  return NextResponse.json({ spot })
}

const editSchema = z.object({
  name: z.string().min(3).max(120),
  description: z.string().min(20).max(2000),
  lat: z.number().min(-90).max(90),
  lng: z.number().min(-180).max(180),
  altitude: z.number().int().min(0).max(10000).optional(),
  difficulty: z.enum(['BEGINNER', 'INTERMEDIATE', 'ADVANCED']).default('BEGINNER'),
  tags: z.array(z.string().max(30)).max(10).default([]),
})

const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp']
const MAX_FILE_SIZE = 5 * 1024 * 1024
const MAX_IMAGES = 5

export async function PATCH(req: NextRequest, { params }: { params: { id: string } }) {
  const session = await getServerSession(authOptions)
  if (!session?.user?.id) return NextResponse.json({ error: 'Não autenticado' }, { status: 401 })

  const spot = await prisma.spot.findUnique({ where: { id: params.id }, select: { id: true, authorId: true, images: true } })
  if (!spot) return NextResponse.json({ error: 'Spot não encontrado' }, { status: 404 })

  const isOwner = spot.authorId === session.user.id
  const isMod = ['MODERATOR', 'ADMIN'].includes((session.user as any).role ?? '')
  if (!isOwner && !isMod) return NextResponse.json({ error: 'Sem permissão' }, { status: 403 })

  const formData = await req.formData().catch(() => null)
  if (!formData) return NextResponse.json({ error: 'Invalid form data' }, { status: 400 })

  const raw = {
    name: formData.get('name'),
    description: formData.get('description'),
    lat: parseFloat(formData.get('lat') as string),
    lng: parseFloat(formData.get('lng') as string),
    altitude: formData.get('altitude') ? parseInt(formData.get('altitude') as string) : undefined,
    difficulty: formData.get('difficulty'),
    tags: (() => { try { return JSON.parse(formData.get('tags') as string ?? '[]') } catch { return [] } })(),
  }

  const parsed = editSchema.safeParse(raw)
  if (!parsed.success) return NextResponse.json({ error: parsed.error.flatten() }, { status: 422 })

  const { name, description, lat, lng, altitude, difficulty, tags } = parsed.data

  const keepImages: string[] = (() => {
    try { return JSON.parse(formData.get('keepImages') as string ?? '[]') } catch { return [] }
  })()

  const imageFiles = formData.getAll('images') as File[]
  const validImages = imageFiles.filter(
    (f) => f instanceof File && f.size > 0 && f.size <= MAX_FILE_SIZE && ALLOWED_TYPES.includes(f.type)
  ).slice(0, Math.max(0, MAX_IMAGES - keepImages.length))

  const newPaths: string[] = []
  if (validImages.length > 0) {
    const uploadDir = uploadDiskPath('spots', spot.id)
    await mkdir(uploadDir, { recursive: true })
    for (const file of validImages) {
      const ext = file.type === 'image/png' ? 'png' : file.type === 'image/webp' ? 'webp' : 'jpg'
      const filename = `${Date.now()}-${Math.random().toString(36).slice(2)}.${ext}`
      await writeFile(uploadDiskPath('spots', spot.id, filename), Buffer.from(await file.arrayBuffer()))
      newPaths.push(uploadUrlPath('spots', spot.id, filename))
    }
  }

  const finalImages = [...keepImages, ...newPaths]

  await prisma.spot.update({
    where: { id: spot.id },
    data: {
      name: DOMPurify.sanitize(name),
      description: DOMPurify.sanitize(description),
      lat, lng, altitude, difficulty, tags,
      images: finalImages,
      coverImage: finalImages[0] ?? null,
    },
  })

  return NextResponse.json({ ok: true })
}
