import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { getServerSession } from 'next-auth'
import { authOptions } from '@/lib/auth'
import { listApprovedSpots } 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'

const listSchema = z.object({
  cursor: z.string().optional(),
  take: z.coerce.number().min(1).max(50).optional(),
  lat: z.coerce.number().optional(),
  lng: z.coerce.number().optional(),
  radius: z.coerce.number().min(1).max(500).optional(),
  difficulty: z.enum(['BEGINNER', 'INTERMEDIATE', 'ADVANCED']).optional(),
})

const createSchema = 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 GET(req: NextRequest) {
  const { searchParams } = req.nextUrl
  const parsed = listSchema.safeParse(Object.fromEntries(searchParams))
  if (!parsed.success) return NextResponse.json({ error: parsed.error.flatten() }, { status: 422 })

  const { cursor, take, lat, lng, radius, difficulty } = parsed.data
  const result = await listApprovedSpots({ cursor, take, lat, lng, radiusKm: radius, difficulty })
  return NextResponse.json(result)
}

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

  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 = createSchema.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 spot = await prisma.spot.create({
    data: {
      name: DOMPurify.sanitize(name),
      description: DOMPurify.sanitize(description),
      lat, lng, altitude, difficulty,
      tags,
      authorId: session.user.id,
      status: 'PENDING',
    },
    select: { id: true, name: true, status: true },
  })

  // Image uploads
  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, MAX_IMAGES)

  if (validImages.length > 0) {
    const uploadDir = uploadDiskPath('spots', spot.id)
    await mkdir(uploadDir, { recursive: true })

    const savedPaths: string[] = []
    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()))
      savedPaths.push(uploadUrlPath('spots', spot.id, filename))
    }

    if (savedPaths.length > 0) {
      await prisma.spot.update({
        where: { id: spot.id },
        data: { coverImage: savedPaths[0], images: savedPaths },
      })
    }
  }

  return NextResponse.json({ spot }, { status: 201 })
}
