import { NextResponse } from "next/server"
import { createClient } from "@/lib/supabase/server"
import { isAdminUser } from "@/lib/auth/is-admin"
import { normalizeResourceTypeBookingFields, type ResourceTypeBookingFields } from "@/lib/booking"
import {
  reservationFitsResourceTypeWindow,
  reservationMeetsMinSlotDuration,
} from "@/lib/booking/server-window"
import { isAllowedUntilStart, resolveReservationRules } from "@/lib/reservations/rules"

type UpdateReservationBody = {
  resourceId?: string
  startAt?: string
  endAt?: string
  notes?: string | null
}

export async function PATCH(
  request: Request,
  { params }: { params: Promise<{ id: string }> },
) {
  const { id } = await params
  const reservationId = id?.trim()

  if (!reservationId) {
    return NextResponse.json({ error: "El id de la reserva es obligatorio" }, { status: 400 })
  }

  const body = (await request.json().catch(() => ({}))) as UpdateReservationBody
  const resourceId = typeof body.resourceId === "string" ? body.resourceId.trim() : ""
  const startAt = typeof body.startAt === "string" ? body.startAt : ""
  const endAt = typeof body.endAt === "string" ? body.endAt : ""
  const notes = typeof body.notes === "string" ? body.notes.trim() : null

  if (!resourceId || !startAt || !endAt) {
    return NextResponse.json(
      { error: "resourceId, startAt y endAt son obligatorios" },
      { status: 400 },
    )
  }

  const startDate = new Date(startAt)
  const endDate = new Date(endAt)
  if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime()) || endDate <= startDate) {
    return NextResponse.json({ error: "El rango de fechas es inválido" }, { status: 400 })
  }

  const supabase = await createClient()
  const {
    data: { user },
    error: userError,
  } = await supabase.auth.getUser()

  if (userError || !user) {
    return NextResponse.json({ error: "No autorizado" }, { status: 401 })
  }

  const { data: reservation, error: reservationError } = await supabase
    .from("reservations")
    .select("id, user_id, resource_id, start_at, status")
    .eq("id", reservationId)
    .maybeSingle()

  if (reservationError) {
    return NextResponse.json({ error: "No se pudo consultar la reserva" }, { status: 500 })
  }
  if (!reservation) {
    return NextResponse.json({ error: "Reserva no encontrada" }, { status: 404 })
  }

  const canManage = reservation.user_id === user.id || isAdminUser(user)
  if (!canManage) {
    return NextResponse.json({ error: "No tienes permisos para editar esta reserva" }, { status: 403 })
  }
  if (reservation.status !== "confirmed") {
    return NextResponse.json({ error: "Solo se pueden editar reservas confirmadas" }, { status: 409 })
  }

  const { data: resource, error: resourceError } = await supabase
    .from("resources")
    .select(
      `
      id,
      resource_type_id,
      resource_types (
        booking_window_start,
        booking_window_end,
        slot_size,
        time_granularity
      )
    `,
    )
    .eq("id", resourceId)
    .maybeSingle()

  if (resourceError) {
    return NextResponse.json({ error: "No se pudo consultar el recurso" }, { status: 500 })
  }
  if (!resource) {
    return NextResponse.json({ error: "Recurso no encontrado" }, { status: 404 })
  }

  const raw = resource as unknown as {
    resource_types?: Partial<ResourceTypeBookingFields> | Partial<ResourceTypeBookingFields>[] | null
  }
  const tr = raw.resource_types
  const typeRow = Array.isArray(tr) ? tr[0] : tr
  const typeFields = normalizeResourceTypeBookingFields(typeRow ?? null)
  if (!reservationFitsResourceTypeWindow({ startAt: startDate, endAt: endDate, type: typeFields })) {
    return NextResponse.json(
      { error: "La reserva debe quedar dentro de la ventana horaria del tipo de recurso (mismo día civil)" },
      { status: 409 },
    )
  }
  if (!reservationMeetsMinSlotDuration({ startAt: startDate, endAt: endDate, type: typeFields })) {
    return NextResponse.json(
      { error: "La duración no cumple la duración mínima configurada para el tipo de recurso" },
      { status: 409 },
    )
  }

  const { data: policies, error: policyError } = await supabase.from("resource_policies").select("*")
  if (policyError) {
    return NextResponse.json({ error: "No se pudieron consultar las políticas de reserva" }, { status: 500 })
  }

  const rules = resolveReservationRules({
    resourceId: resource.id,
    resourceTypeId: resource.resource_type_id,
    policies: policies ?? [],
  })

  const now = new Date()
  const canEditNow = isAllowedUntilStart({
    now,
    startAt: reservation.start_at,
    minutesBeforeStart: rules.editingDeadlineMinutes,
  })
  if (!canEditNow) {
    return NextResponse.json(
      {
        error: "La ventana de edición de esta reserva ya cerró",
        editingDeadlineMinutes: rules.editingDeadlineMinutes,
      },
      { status: 409 },
    )
  }

  const maxStartAllowed = new Date(now.getTime() + rules.bookingAdvanceMinutes * 60 * 1000)
  if (startDate.getTime() <= now.getTime() || startDate.getTime() > maxStartAllowed.getTime()) {
    return NextResponse.json(
      {
        error: "La reserva editada queda fuera de la ventana permitida por la política",
        bookingAdvanceMinutes: rules.bookingAdvanceMinutes,
      },
      { status: 409 },
    )
  }

  const { data: conflicts, error: conflictsError } = await supabase
    .from("reservations")
    .select("id")
    .eq("resource_id", resource.id)
    .in("status", ["confirmed", "checked_in"])
    .lt("start_at", endDate.toISOString())
    .gt("end_at", startDate.toISOString())
    .neq("id", reservation.id)

  if (conflictsError) {
    return NextResponse.json({ error: "No se pudo validar la disponibilidad del horario" }, { status: 500 })
  }
  if (conflicts && conflicts.length > 0) {
    return NextResponse.json({ error: "El horario seleccionado no está disponible" }, { status: 409 })
  }

  const payload: Record<string, unknown> = {
    resource_id: resource.id,
    start_at: startDate.toISOString(),
    end_at: endDate.toISOString(),
    notes,
    reconfirmation_status: "pending",
    reconfirmed_at: null,
    reminder_sent_at: null,
  }

  const { data: updated, error: updateError } = await (supabase.from("reservations") as any)
    .update(payload)
    .eq("id", reservation.id)
    .eq("status", "confirmed")
    .select("id, resource_id, start_at, end_at, status, notes")
    .maybeSingle()

  if (updateError) {
    return NextResponse.json({ error: "No se pudo actualizar la reserva" }, { status: 500 })
  }
  if (!updated) {
    return NextResponse.json({ error: "No se pudo actualizar la reserva" }, { status: 409 })
  }

  return NextResponse.json({ ok: true, reservation: updated })
}
