"use client"

import { useState, useEffect, useCallback, useMemo, useRef } from "react"
import { createClient } from "@/lib/supabase/client"
import { useSearchParams, useRouter, usePathname } from "next/navigation"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Badge } from "@/components/ui/badge"
import { Calendar } from "@/components/ui/calendar"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { addDays, format, startOfDay, endOfDay, isBefore, setHours, setMinutes } from "date-fns"
import { es } from "date-fns/locale"
import { Monitor, MapPin, Filter, ChevronLeft, Users, Search, Trash2 } from "lucide-react"
import { cn } from "@/lib/utils"
import { ReservationDialog } from "@/components/reservations/reservation-dialog"
import {
  bookingFieldsToSlotStarts,
  DEFAULT_BOOKING_FIELDS,
  formatSlotEndLabel,
  isSlotAvailable,
  mergeSlotStartsForTypes,
  normalizeResourceTypeBookingFields,
  slotStartIsInTypeWindow,
  timeGranularityToMinutes,
  type ResourceTypeBookingFields,
} from "@/lib/booking"
import type { Database } from "@/lib/supabase/database.types"
import {
  BOOKING_CALENDAR_LOOKAHEAD_DAYS,
  getAdvanceRestriction,
  type PolicyRow,
} from "@/lib/reservations/advance-restriction"
import { Input } from "@/components/ui/input"
import { Alert, AlertDescription } from "@/components/ui/alert"
import { buildLocationChildrenMap, getLocationPathIds, type LocationRow } from "@/lib/locations/tree"
import { DynamicIcon } from "@/components/ui/dynamic-icon"
import { PolicyDisabledTooltip } from "@/components/reservations/policy-disabled-tooltip"

type Resource = Database["public"]["Tables"]["resources"]["Row"] & {
  resource_types: {
    name: string
    slug: string
    icon: string | null
    booking_window_start?: string | null
    booking_window_end?: string | null
    slot_size?: string | null
    time_granularity?: string | null
  } | null
}
type Reservation = Database["public"]["Tables"]["reservations"]["Row"]
type ResourceType = Database["public"]["Tables"]["resource_types"]["Row"]

function getResourceLocationPath(resource: Resource) {
  const metadata = (resource.metadata ?? {}) as { locationPathValues?: string[] }
  if (!Array.isArray(metadata.locationPathValues) || metadata.locationPathValues.length === 0) {
    return null
  }
  return metadata.locationPathValues.join(" > ")
}

const POLLING_INTERVAL_MS = 10_000

export default function ReservationsPage() {
  const searchParams = useSearchParams()
  const router = useRouter()
  const pathname = usePathname()
  const [resources, setResources] = useState<Resource[]>([])
  const [reservations, setReservations] = useState<Reservation[]>([])
  const [resourceTypes, setResourceTypes] = useState<ResourceType[]>([])
  const [locations, setLocations] = useState<LocationRow[]>([])
  const [selectedLocationByDepth, setSelectedLocationByDepth] = useState<string[]>([])
  const [loading, setLoading] = useState(true)
  const [selectedDate, setSelectedDate] = useState<Date>(() => new Date())
  const [filterType, setFilterType] = useState<string>("all")
  const [filterTag, setFilterTag] = useState<string>("all")
  const [dialogOpen, setDialogOpen] = useState(false)
  const [selectedResource, setSelectedResource] = useState<Resource | null>(null)
  const [selectedTimeSlot, setSelectedTimeSlot] = useState<{ start: string; end: string } | null>(null)
  const [filterPopoverOpen, setFilterPopoverOpen] = useState(false)
  type FilterStep = "list" | "tipo" | "ubicacion" | "dia" | "etiqueta"
  const [filterStep, setFilterStep] = useState<FilterStep>("list")
  const [filterMounted, setFilterMounted] = useState(false)
  const [searchName, setSearchName] = useState("")
  const [policies, setPolicies] = useState<PolicyRow[]>([])
  const [hasResolvedTypeFilterFromQuery, setHasResolvedTypeFilterFromQuery] = useState(false)
  useEffect(() => setFilterMounted(true), [])
  const supabase = useMemo(() => createClient(), [])
  const pollInFlightRef = useRef(false)
  const didHydrateFiltersFromUrlRef = useRef(false)
  const dateWasProvidedByUrlRef = useRef(false)
  const didAutoShiftDefaultDateRef = useRef(false)
  const queryType = searchParams.get("type")
  const locationChildrenMap = useMemo(() => buildLocationChildrenMap(locations), [locations])
  const selectedLocationPathIds = useMemo(
    () =>
      getLocationPathIds({
        selectedByDepth: selectedLocationByDepth,
        childrenMap: locationChildrenMap,
      }),
    [selectedLocationByDepth, locationChildrenMap],
  )
  const selectedLocationId =
    selectedLocationPathIds.length > 0 ? selectedLocationPathIds[selectedLocationPathIds.length - 1] : null
  const isDefaultDaySelected = useMemo(
    () => startOfDay(selectedDate).getTime() === startOfDay(new Date()).getTime(),
    [selectedDate],
  )

  useEffect(() => {
    if (didHydrateFiltersFromUrlRef.current) return

    const rawDate = searchParams.get("date")
    if (rawDate) {
      const parsed = new Date(`${rawDate}T00:00:00`)
      if (!Number.isNaN(parsed.getTime())) {
        const today = startOfDay(new Date())
        setSelectedDate(isBefore(startOfDay(parsed), today) ? today : parsed)
        dateWasProvidedByUrlRef.current = true
      }
    }

    const rawTag = searchParams.get("tag")
    if (rawTag && rawTag !== "all") {
      setFilterTag(rawTag)
    }

    const rawLocation = searchParams.get("location")
    if (rawLocation) {
      const nextPath = rawLocation
        .split(",")
        .map((segment) => segment.trim())
        .filter(Boolean)
        .slice(0, 20)

      if (nextPath.length > 0) {
        setSelectedLocationByDepth(nextPath)
      }
    }

    const rawSearch = searchParams.get("q")
    if (rawSearch) {
      setSearchName(rawSearch)
    }

    didHydrateFiltersFromUrlRef.current = true
  }, [searchParams])

  useEffect(() => {
    didAutoShiftDefaultDateRef.current = false
    if (!dateWasProvidedByUrlRef.current) {
      setSelectedDate(startOfDay(new Date()))
    }
  }, [filterType])

  useEffect(() => {
    if (!didHydrateFiltersFromUrlRef.current || !hasResolvedTypeFilterFromQuery) return

    const nextParams = new URLSearchParams(searchParams.toString())
    if (filterType !== "all") {
      const selectedType = resourceTypes.find((type) => type.id === filterType)
      nextParams.set("type", selectedType?.slug ?? filterType)
    } else {
      nextParams.delete("type")
    }

    if (selectedLocationByDepth.length > 0) {
      nextParams.set("location", selectedLocationByDepth.join(","))
    } else {
      nextParams.delete("location")
    }

    if (filterTag !== "all") {
      nextParams.set("tag", filterTag)
    } else {
      nextParams.delete("tag")
    }

    const trimmedSearchName = searchName.trim()
    if (trimmedSearchName) {
      nextParams.set("q", trimmedSearchName)
    } else {
      nextParams.delete("q")
    }

    if (!isDefaultDaySelected) {
      nextParams.set("date", format(selectedDate, "yyyy-MM-dd"))
    } else {
      nextParams.delete("date")
    }

    const currentQuery = searchParams.toString()
    const nextQuery = nextParams.toString()
    if (currentQuery !== nextQuery) {
      router.replace(nextQuery ? `${pathname}?${nextQuery}` : pathname, { scroll: false })
    }
  }, [
    filterType,
    selectedLocationByDepth,
    filterTag,
    searchName,
    selectedDate,
    isDefaultDaySelected,
    resourceTypes,
    hasResolvedTypeFilterFromQuery,
    searchParams,
    router,
    pathname,
  ])

  const refreshReservations = useCallback(async () => {
    const dayStart = startOfDay(selectedDate).toISOString()
    const dayEnd = endOfDay(selectedDate).toISOString()

    const { data: reservationsData } = await supabase
      .from("reservations")
      .select("*")
      .gte("start_at", dayStart)
      .lte("start_at", dayEnd)
      .in("status", ["confirmed", "checked_in"])

    if (reservationsData) setReservations(reservationsData as Reservation[])
  }, [selectedDate, supabase])

  const fetchData = useCallback(async () => {
    setLoading(true)

    try {
      const { data: typesData } = await supabase.from("resource_types").select("*").eq("is_active", true).order("name")
      if (typesData) setResourceTypes(typesData)

      const { data: policiesData } = await supabase.from("resource_policies").select("*")
      if (policiesData) setPolicies(policiesData as PolicyRow[])

      const availableTypes = typesData ?? []
      let effectiveFilterType = filterType
      if (!hasResolvedTypeFilterFromQuery && filterType === "all" && queryType) {
        const normalizedQuery = queryType.toLowerCase()
        const typeFromQuery = availableTypes.find((type) => {
          const slug = type.slug.toLowerCase()
          const id = type.id.toLowerCase()
          return (
            id === normalizedQuery ||
            slug === normalizedQuery ||
            slug.replace(/_/g, "-") === normalizedQuery ||
            slug.replace(/-/g, "_") === normalizedQuery
          )
        })

        if (typeFromQuery) {
          effectiveFilterType = typeFromQuery.id
          setFilterType((current) => (current === "all" ? typeFromQuery.id : current))
        }
      }

      let resourceQuery = supabase
        .from("resources")
        .select(
          `*, resource_types (name, slug, icon, booking_window_start, booking_window_end, slot_size, time_granularity)`,
        )
        .eq("is_active", true)
        .order("name")

      if (effectiveFilterType !== "all") {
        resourceQuery = resourceQuery.eq("resource_type_id", effectiveFilterType)
      }

      const { data: resourcesData } = await resourceQuery
      if (resourcesData) setResources(resourcesData as Resource[])

      await refreshReservations()
    } finally {
      setLoading(false)
      setHasResolvedTypeFilterFromQuery(true)
    }
  }, [supabase, filterType, queryType, refreshReservations, hasResolvedTypeFilterFromQuery])

  useEffect(() => {
    void fetchData()
  }, [fetchData])

  useEffect(() => {
    let cancelled = false
    const loadLocations = async () => {
      const response = await fetch("/api/locations")
      const payload = (await response.json().catch(() => null)) as
        | { locations?: LocationRow[] }
        | null
      if (!response.ok || cancelled) return
      setLocations(payload?.locations ?? [])
    }

    void loadLocations()
    return () => {
      cancelled = true
    }
  }, [])

  useEffect(() => {
    const runPollingRefresh = async () => {
      if (document.visibilityState !== "visible") return
      if (loading || pollInFlightRef.current) return

      pollInFlightRef.current = true
      try {
        await refreshReservations()
      } finally {
        pollInFlightRef.current = false
      }
    }

    const intervalId = window.setInterval(() => {
      void runPollingRefresh()
    }, POLLING_INTERVAL_MS)

    const handleVisibilityChange = () => {
      if (document.visibilityState === "visible") {
        void runPollingRefresh()
      }
    }

    document.addEventListener("visibilitychange", handleVisibilityChange)

    return () => {
      window.clearInterval(intervalId)
      document.removeEventListener("visibilitychange", handleVisibilityChange)
    }
  }, [loading, refreshReservations])

  useEffect(() => {
    setFilterTag("all")
  }, [filterType])

  const resourcesForTags = useMemo(() => {
    if (filterType !== "all") return resources.filter((r) => r.resource_type_id === filterType)
    return resources
  }, [resources, filterType])

  const tagOptions = useMemo(() => {
    const s = new Set<string>()
    for (const r of resourcesForTags) {
      const am = r.amenities as string[] | null
      if (Array.isArray(am)) am.forEach((a) => s.add(a))
    }
    return Array.from(s).sort()
  }, [resourcesForTags])

  const filteredResources = useMemo(() => {
    let scopedResources = resourcesForTags

    if (selectedLocationId) {
      scopedResources = scopedResources.filter((resource) => {
        const metadata = (resource.metadata ?? {}) as { locationPathIds?: string[] }
        return Array.isArray(metadata.locationPathIds) && metadata.locationPathIds.includes(selectedLocationId)
      })
    }

    if (filterTag !== "all") {
      scopedResources = scopedResources.filter((r) => {
        const am = r.amenities as string[] | null
        return Array.isArray(am) && am.includes(filterTag)
      })
    }

    const nameQuery = searchName.trim().toLowerCase()
    if (nameQuery) {
      scopedResources = scopedResources.filter((r) =>
        r.name.toLowerCase().includes(nameQuery)
      )
    }

    return scopedResources
  }, [resourcesForTags, filterTag, selectedLocationId, searchName])

  const slotHeader = useMemo(() => {
    const byType = new Map<string, ResourceTypeBookingFields>()
    for (const r of filteredResources) {
      if (!r.resource_type_id || byType.has(r.resource_type_id)) continue
      byType.set(
        r.resource_type_id,
        normalizeResourceTypeBookingFields(
          r.resource_types as Partial<ResourceTypeBookingFields> | null | undefined,
        ),
      )
    }
    const list = [...byType.values()]
    if (list.length === 0) return bookingFieldsToSlotStarts(DEFAULT_BOOKING_FIELDS)
    return mergeSlotStartsForTypes(list)
  }, [filteredResources])

  const locationLevelOptions = useMemo(() => {
    const levels: Array<{ depth: number; options: LocationRow[] }> = []
    let parentId: string | null = null
    for (let depth = 0; depth < 20; depth += 1) {
      const options = locationChildrenMap.get(parentId) ?? []
      if (options.length === 0) break
      levels.push({ depth, options })
      const selectedAtDepth = selectedLocationByDepth[depth]
      if (!selectedAtDepth) break
      parentId = selectedAtDepth
    }
    return levels
  }, [locationChildrenMap, selectedLocationByDepth])

  const hasBookableSlotsForDate = useCallback(
    (targetDate: Date, dayReservations: Reservation[], scopedResources: Resource[]) => {
      for (const resource of scopedResources) {
        const booking = normalizeResourceTypeBookingFields(
          resource.resource_types as Partial<ResourceTypeBookingFields> | null | undefined,
        )
        const advanceRestriction = getAdvanceRestriction(resource, targetDate, policies, booking)
        if (advanceRestriction.disabled) continue

        const stepMin = timeGranularityToMinutes(String(booking.time_granularity))
        const resourceSlots = bookingFieldsToSlotStarts(booking)

        for (const slot of resourceSlots) {
          if (!slotStartIsInTypeWindow(slot, booking)) continue

          const [slotHour, slotMinute] = slot.split(":").map(Number)
          const slotStart = setMinutes(setHours(targetDate, slotHour), slotMinute)
          const disabledByAdvance =
            !!advanceRestriction.minSlotStart &&
            slotStart.getTime() < advanceRestriction.minSlotStart.getTime()
          if (disabledByAdvance) continue

          if (isSlotAvailable(resource.id, slot, targetDate, dayReservations, stepMin)) {
            return true
          }
        }
      }

      return false
    },
    [policies],
  )

  useEffect(() => {
    if (loading) return
    if (!hasResolvedTypeFilterFromQuery) return
    if (dateWasProvidedByUrlRef.current) return
    if (didAutoShiftDefaultDateRef.current) return
    if (!isDefaultDaySelected) return
    if (filteredResources.length === 0) return
    if (hasBookableSlotsForDate(selectedDate, reservations, filteredResources)) return

    didAutoShiftDefaultDateRef.current = true
    let cancelled = false

    const moveToNextAvailableDate = async () => {
      const today = startOfDay(new Date())
      for (let offset = 1; offset <= BOOKING_CALENDAR_LOOKAHEAD_DAYS; offset += 1) {
        const candidateDate = addDays(today, offset)
        const dayStart = startOfDay(candidateDate).toISOString()
        const dayEnd = endOfDay(candidateDate).toISOString()
        const { data: candidateReservations } = await supabase
          .from("reservations")
          .select("*")
          .gte("start_at", dayStart)
          .lte("start_at", dayEnd)
          .in("status", ["confirmed", "checked_in"])

        if (!candidateReservations) continue

        const hasAvailability = hasBookableSlotsForDate(
          candidateDate,
          candidateReservations as Reservation[],
          filteredResources,
        )
        if (!hasAvailability) continue

        if (!cancelled) {
          setSelectedDate(candidateDate)
        }
        return
      }
    }

    void moveToNextAvailableDate()

    return () => {
      cancelled = true
    }
  }, [
    loading,
    hasResolvedTypeFilterFromQuery,
    isDefaultDaySelected,
    filteredResources,
    selectedDate,
    reservations,
    supabase,
    hasBookableSlotsForDate,
  ])

  const clearTypeFilter = useCallback(() => {
    setHasResolvedTypeFilterFromQuery(true)
    setFilterType("all")
  }, [])

  const clearLocationFilter = useCallback(() => {
    setSelectedLocationByDepth([])
  }, [])

  const clearDateFilter = useCallback(() => {
    dateWasProvidedByUrlRef.current = false
    didAutoShiftDefaultDateRef.current = false
    setSelectedDate(startOfDay(new Date()))
  }, [])

  const clearTagFilter = useCallback(() => {
    setFilterTag("all")
  }, [])

  const handleSlotClick = (resource: Resource, timeSlot: string) => {
    const booking = normalizeResourceTypeBookingFields(
      resource.resource_types as Partial<ResourceTypeBookingFields> | null | undefined,
    )
    const stepMin = timeGranularityToMinutes(String(booking.time_granularity))
    if (!slotStartIsInTypeWindow(timeSlot, booking)) return
    if (!isSlotAvailable(resource.id, timeSlot, selectedDate, reservations, stepMin)) return

    setSelectedResource(resource)
    setSelectedTimeSlot({
      start: timeSlot,
      end: formatSlotEndLabel(selectedDate, timeSlot, stepMin),
    })
    setDialogOpen(true)
  }

  const handleDialogClose = () => {
    setDialogOpen(false)
    setSelectedResource(null)
    setSelectedTimeSlot(null)
    void refreshReservations()
  }

  return (
    <div className="space-y-[var(--ds-space-4x)]">
      <div className="rounded-[var(--ds-radius-l)] bg-[var(--ds-blueprimary-100)] px-[var(--ds-space-4x)] py-[var(--ds-space-3x)] shadow-[var(--ds-shadow-4dp)]">
        <h1 className="ds-type-global-l ds-type-semibold text-[var(--ds-blueprimary-800)]">Reservas</h1>
        <p className="mt-[var(--ds-space-1x)] ds-type-global-s text-[var(--ds-text-neutral-lighter)]">
          Selecciona un recurso y horario para reservar
        </p>
      </div>

      <div className="flex items-center gap-[var(--ds-space-2x)]">
        <div className="relative min-w-0 flex-1 sm:max-w-[calc(var(--ds-space-5x)*8)]">
          <Search className="absolute left-[var(--ds-space-15x)] top-1/2 h-[var(--ds-space-2x)] w-[var(--ds-space-2x)] -translate-y-1/2 text-[var(--ds-text-neutral-lighter)]" />
          <Input
            type="search"
            placeholder="Buscar por nombre de recurso"
            value={searchName}
            onChange={(e) => setSearchName(e.target.value)}
            className="h-[var(--ds-space-5x)] rounded-[var(--ds-radius-m)] border-[var(--ds-neutral-300)] bg-[var(--background)] pl-[var(--ds-space-5x)] pr-[var(--ds-space-15x)] ds-type-global-xs text-[var(--ds-text-neutral-default)] placeholder:text-[var(--ds-text-neutral-lighter)]"
            aria-label="Buscar por nombre de recurso"
          />
        </div>

        <div className="ml-auto shrink-0">
          {!filterMounted ? (
            <Button
              variant="outline"
              className="h-[var(--ds-space-5x)] gap-[var(--ds-space-1x)] rounded-[var(--ds-radius-m)] border-[var(--ds-brand-400)] bg-[var(--ds-blueprimary-100)] px-[var(--ds-space-2x)] ds-type-global-xs text-[var(--ds-blueprimary-800)] hover:bg-[var(--ds-brand-400)] hover:text-[var(--background)]"
              aria-hidden
            >
              <Filter className="h-[var(--ds-space-2x)] w-[var(--ds-space-2x)]" />
              Filtrar
            </Button>
          ) : (
            <Popover
              open={filterPopoverOpen}
              onOpenChange={(open) => {
                setFilterPopoverOpen(open)
                if (!open) setFilterStep("list")
              }}
            >
              <PopoverTrigger asChild>
                <Button
                  variant="outline"
                  className="h-[var(--ds-space-5x)] gap-[var(--ds-space-1x)] rounded-[var(--ds-radius-m)] border-[var(--ds-brand-400)] bg-[var(--ds-blueprimary-100)] px-[var(--ds-space-2x)] ds-type-global-xs text-[var(--ds-blueprimary-800)] hover:bg-[var(--ds-brand-400)] hover:text-[var(--background)]"
                >
                  <Filter className="h-[var(--ds-space-2x)] w-[var(--ds-space-2x)]" />
                  Filtrar
                </Button>
              </PopoverTrigger>
              <PopoverContent
                className="w-[calc(var(--ds-space-5x)*8)] overflow-hidden rounded-[var(--ds-radius-l)] border-[var(--ds-brand-400)] bg-[var(--background)] p-0 shadow-[var(--ds-shadow-8dp)]"
                align="end"
                side="bottom"
                sideOffset={8}
                avoidCollisions={false}
              >
                {filterStep === "list" ? (
                  <div className="flex flex-col">
                    <div className="rounded-t-[var(--ds-radius-l)] border-b border-[var(--ds-brand-400)] bg-[var(--ds-blueprimary-100)] px-[var(--ds-space-3x)] py-[var(--ds-space-2x)]">
                      <p className="ds-type-global-s ds-type-semibold text-[var(--ds-blueprimary-800)]">Filtros</p>
                      <p className="mt-[var(--ds-space-05x)] ds-type-global-xxs text-[var(--ds-text-neutral-lighter)]">
                        Elige un tipo de filtro para aplicar
                      </p>
                    </div>
                    <div className="flex items-center justify-between rounded-[var(--ds-radius-s)] px-[var(--ds-space-3x)] py-[var(--ds-space-2x)] transition-colors hover:bg-[var(--ds-blueprimary-100)]">
                      <button
                        type="button"
                        onClick={() => setFilterStep("tipo")}
                        className="flex min-w-0 flex-1 items-center justify-between text-left ds-type-global-xs text-[var(--ds-text-neutral-default)]"
                      >
                        <span>Tipo de recurso</span>
                        <span className="ds-type-global-xxs text-[var(--ds-text-neutral-lighter)]">
                          {filterType === "all" ? "Todos" : resourceTypes.find((t) => t.id === filterType)?.name ?? "—"}
                        </span>
                      </button>
                      {filterType !== "all" && (
                        <button
                          type="button"
                          aria-label="Limpiar filtro de tipo de recurso"
                          onClick={clearTypeFilter}
                          className="ml-[var(--ds-space-1x)] flex h-[var(--ds-space-3x)] w-[var(--ds-space-3x)] items-center justify-center rounded-[var(--ds-radius-s)] text-[var(--ds-text-neutral-lighter)] transition-colors hover:bg-[var(--ds-blueprimary-100)] hover:text-[var(--ds-blueprimary-800)]"
                        >
                          <Trash2 className="h-[var(--ds-space-15x)] w-[var(--ds-space-15x)]" />
                        </button>
                      )}
                    </div>
                    <div className="flex items-center justify-between rounded-[var(--ds-radius-s)] px-[var(--ds-space-3x)] py-[var(--ds-space-2x)] transition-colors hover:bg-[var(--ds-blueprimary-100)]">
                      <button
                        type="button"
                        onClick={() => setFilterStep("ubicacion")}
                        className="flex min-w-0 flex-1 items-center justify-between text-left ds-type-global-xs text-[var(--ds-text-neutral-default)]"
                      >
                        <span>Ubicación</span>
                        <span className="ds-type-global-xxs text-[var(--ds-text-neutral-lighter)]">
                          {selectedLocationPathIds.length === 0
                            ? "Sin selección"
                            : locations.find((l) => l.id === selectedLocationId)?.value ?? "—"}
                        </span>
                      </button>
                      {selectedLocationPathIds.length > 0 && (
                        <button
                          type="button"
                          aria-label="Limpiar filtro de ubicación"
                          onClick={clearLocationFilter}
                          className="ml-[var(--ds-space-1x)] flex h-[var(--ds-space-3x)] w-[var(--ds-space-3x)] items-center justify-center rounded-[var(--ds-radius-s)] text-[var(--ds-text-neutral-lighter)] transition-colors hover:bg-[var(--ds-blueprimary-100)] hover:text-[var(--ds-blueprimary-800)]"
                        >
                          <Trash2 className="h-[var(--ds-space-15x)] w-[var(--ds-space-15x)]" />
                        </button>
                      )}
                    </div>
                    <div className="flex items-center justify-between rounded-[var(--ds-radius-s)] px-[var(--ds-space-3x)] py-[var(--ds-space-2x)] transition-colors hover:bg-[var(--ds-blueprimary-100)]">
                      <button
                        type="button"
                        onClick={() => setFilterStep("dia")}
                        className="flex min-w-0 flex-1 items-center justify-between text-left ds-type-global-xs text-[var(--ds-text-neutral-default)]"
                      >
                        <span>Día</span>
                        <span className="ds-type-global-xxs text-[var(--ds-text-neutral-lighter)]">
                          {format(selectedDate, "EEE d MMM yyyy", { locale: es })}
                        </span>
                      </button>
                      {!isDefaultDaySelected && (
                        <button
                          type="button"
                          aria-label="Limpiar filtro de día"
                          onClick={clearDateFilter}
                          className="ml-[var(--ds-space-1x)] flex h-[var(--ds-space-3x)] w-[var(--ds-space-3x)] items-center justify-center rounded-[var(--ds-radius-s)] text-[var(--ds-text-neutral-lighter)] transition-colors hover:bg-[var(--ds-blueprimary-100)] hover:text-[var(--ds-blueprimary-800)]"
                        >
                          <Trash2 className="h-[var(--ds-space-15x)] w-[var(--ds-space-15x)]" />
                        </button>
                      )}
                    </div>
                    <div className="flex items-center justify-between rounded-[var(--ds-radius-s)] px-[var(--ds-space-3x)] py-[var(--ds-space-2x)] transition-colors hover:bg-[var(--ds-blueprimary-100)]">
                      <button
                        type="button"
                        onClick={() => setFilterStep("etiqueta")}
                        className="flex min-w-0 flex-1 items-center justify-between text-left ds-type-global-xs text-[var(--ds-text-neutral-default)]"
                      >
                        <span>Etiqueta</span>
                        <span className="ds-type-global-xxs text-[var(--ds-text-neutral-lighter)]">
                          {filterTag === "all" ? "Todas" : filterTag}
                        </span>
                      </button>
                      {filterTag !== "all" && (
                        <button
                          type="button"
                          aria-label="Limpiar filtro de etiqueta"
                          onClick={clearTagFilter}
                          className="ml-[var(--ds-space-1x)] flex h-[var(--ds-space-3x)] w-[var(--ds-space-3x)] items-center justify-center rounded-[var(--ds-radius-s)] text-[var(--ds-text-neutral-lighter)] transition-colors hover:bg-[var(--ds-blueprimary-100)] hover:text-[var(--ds-blueprimary-800)]"
                        >
                          <Trash2 className="h-[var(--ds-space-15x)] w-[var(--ds-space-15x)]" />
                        </button>
                      )}
                    </div>
                  </div>
                ) : (
                  <div className="flex flex-col">
                    <div className="flex items-center gap-[var(--ds-space-1x)] rounded-t-[var(--ds-radius-l)] border-b border-[var(--ds-brand-400)] bg-[var(--ds-blueprimary-100)] px-[var(--ds-space-2x)] py-[var(--ds-space-2x)]">
                      <Button
                        type="button"
                        variant="ghost"
                        size="sm"
                        className="h-[var(--ds-space-4x)] w-[var(--ds-space-4x)] shrink-0 rounded-[var(--ds-radius-s)] p-0 text-[var(--ds-blueprimary-800)] hover:bg-[var(--background)]"
                        onClick={() => setFilterStep("list")}
                      >
                        <ChevronLeft className="h-[var(--ds-space-2x)] w-[var(--ds-space-2x)]" />
                      </Button>
                      <span className="ds-type-global-s ds-type-semibold text-[var(--ds-blueprimary-800)]">
                        {filterStep === "tipo" && "Tipo de recurso"}
                        {filterStep === "ubicacion" && "Ubicación"}
                        {filterStep === "dia" && "Día"}
                        {filterStep === "etiqueta" && "Etiqueta"}
                      </span>
                    </div>
                    <div className="p-[var(--ds-space-3x)]">
                      {filterStep === "tipo" && (
                        <div className="flex flex-col gap-[var(--ds-space-2x)]">
                          <Select
                            value={filterType}
                            onValueChange={(v) => {
                              setFilterType(v)
                              setFilterStep("list")
                            }}
                          >
                            <SelectTrigger className="w-full rounded-[var(--ds-radius-m)] border-[var(--ds-brand-400)] bg-[var(--ds-blueprimary-100)] ds-type-global-xs text-[var(--ds-blueprimary-800)]">
                              <SelectValue placeholder="Todos los tipos" />
                            </SelectTrigger>
                            <SelectContent>
                              <SelectItem value="all">Todos los tipos</SelectItem>
                              {resourceTypes.map((type) => (
                                <SelectItem key={type.id} value={type.id}>
                                  {type.name}
                                </SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                        </div>
                      )}
                      {filterStep === "ubicacion" && (
                        <div className="flex flex-col gap-[var(--ds-space-3x)]">
                          {locationLevelOptions.length === 0 ? (
                            <p className="ds-type-global-xs text-[var(--ds-text-neutral-lighter)]">
                              No hay ubicaciones cargadas.
                            </p>
                          ) : (
                            locationLevelOptions.map((level, index) => (
                              <div key={level.depth} className="flex flex-col gap-[var(--ds-space-05x)]">
                                <span className="ds-type-global-xxs text-[var(--ds-text-neutral-lighter)]">
                                  Nivel {index + 1}
                                </span>
                                <Select
                                  value={selectedLocationByDepth[index] ?? "__none__"}
                                  onValueChange={(value) => {
                                    setSelectedLocationByDepth((prev) => {
                                      const next = prev.slice(0, index)
                                      if (value !== "__none__") next[index] = value
                                      return next
                                    })
                                  }}
                                >
                                  <SelectTrigger className="w-full rounded-[var(--ds-radius-m)] border-[var(--ds-brand-400)] bg-[var(--ds-blueprimary-100)] ds-type-global-xs text-[var(--ds-blueprimary-800)]">
                                    <SelectValue placeholder="Sin selección" />
                                  </SelectTrigger>
                                  <SelectContent>
                                    <SelectItem value="__none__">Sin selección</SelectItem>
                                    {level.options.map((location) => (
                                      <SelectItem key={location.id} value={location.id}>
                                        {location.value}
                                      </SelectItem>
                                    ))}
                                  </SelectContent>
                                </Select>
                              </div>
                            ))
                          )}
                          <Button
                            type="button"
                            variant="outline"
                            size="sm"
                            className="rounded-[var(--ds-radius-m)] border-[var(--ds-brand-400)] bg-[var(--ds-blueprimary-100)] ds-type-global-xs text-[var(--ds-blueprimary-800)] hover:bg-[var(--ds-brand-400)] hover:text-[var(--background)]"
                            onClick={() => setFilterStep("list")}
                          >
                            Listo
                          </Button>
                        </div>
                      )}
                      {filterStep === "dia" && (
                        <div className="flex flex-col gap-[var(--ds-space-2x)]">
                          <Calendar
                            mode="single"
                            selected={selectedDate}
                            onSelect={(date) => date && setSelectedDate(date)}
                            disabled={(date) => isBefore(startOfDay(date), startOfDay(new Date()))}
                            locale={es}
                          />
                          <Button
                            type="button"
                            variant="outline"
                            size="sm"
                            className="rounded-[var(--ds-radius-m)] border-[var(--ds-brand-400)] bg-[var(--ds-blueprimary-100)] ds-type-global-xs text-[var(--ds-blueprimary-800)] hover:bg-[var(--ds-brand-400)] hover:text-[var(--background)]"
                            onClick={() => setFilterStep("list")}
                          >
                            Listo
                          </Button>
                        </div>
                      )}
                      {filterStep === "etiqueta" && (
                        <div className="flex flex-col gap-[var(--ds-space-2x)]">
                          <Select
                            value={filterTag}
                            onValueChange={(v) => {
                              setFilterTag(v)
                              setFilterStep("list")
                            }}
                          >
                            <SelectTrigger className="w-full rounded-[var(--ds-radius-m)] border-[var(--ds-brand-400)] bg-[var(--ds-blueprimary-100)] ds-type-global-xs text-[var(--ds-blueprimary-800)]">
                              <SelectValue placeholder="Todas" />
                            </SelectTrigger>
                            <SelectContent>
                              <SelectItem value="all">Todas las etiquetas</SelectItem>
                              {tagOptions.map((t) => (
                                <SelectItem key={t} value={t}>
                                  {t}
                                </SelectItem>
                              ))}
                            </SelectContent>
                          </Select>
                        </div>
                      )}
                    </div>
                  </div>
                )}
              </PopoverContent>
            </Popover>
          )}
        </div>
      </div>

      {loading ? (
        <div className="flex items-center justify-center py-[calc(var(--ds-space-3x)*2)]">
          <div className="h-[var(--ds-space-4x)] w-[var(--ds-space-4x)] animate-spin rounded-full border-[var(--ds-space-05x)] border-[var(--ds-brand-400)] border-t-transparent" />
        </div>
      ) : (
        <div className="space-y-[var(--ds-space-2x)]">
          {filteredResources.map((resource) => {
            const resourceImageUrl = (resource.metadata as { image_url?: string } | null)?.image_url
            const hasImage = !!resourceImageUrl?.trim()
            const typeBooking = normalizeResourceTypeBookingFields(
              resource.resource_types as Partial<ResourceTypeBookingFields> | null | undefined,
            )
            const advanceRestriction = getAdvanceRestriction(resource, selectedDate, policies, typeBooking)

            return (
              <Card
                key={resource.id}
                className={cn(
                  "overflow-hidden rounded-[var(--ds-radius-l)] border-[var(--ds-neutral-200)] bg-[var(--background)] shadow-[var(--ds-shadow-4dp)]",
                  hasImage ? "flex flex-row p-0" : "py-[var(--ds-space-3x)]",
                  advanceRestriction.disabled && "opacity-75"
                )}
              >
                <div className={cn("flex min-w-0 flex-1 flex-col", hasImage && "py-[var(--ds-space-3x)]")}>
                  <CardHeader className="px-[var(--ds-space-3x)] pb-[var(--ds-space-2x)]">
                    <div className="flex items-start justify-between">
                      <div className="flex items-center gap-[var(--ds-space-2x)]">
                        <div className="flex h-[var(--ds-space-5x)] w-[var(--ds-space-5x)] shrink-0 items-center justify-center rounded-[var(--ds-radius-m)] bg-[var(--ds-blueprimary-100)] text-[var(--ds-brand-400)]">
                          <DynamicIcon
                            name={resource.resource_types?.icon}
                            className="h-[calc(var(--ds-space-2x)+var(--ds-space-05x))] w-[calc(var(--ds-space-2x)+var(--ds-space-05x))]"
                          />
                        </div>
                        <div className="min-w-0">
                          <CardTitle className="ds-type-global-s ds-type-semibold text-[var(--ds-text-neutral-default)]">
                            {resource.name}
                          </CardTitle>
                          <CardDescription className="mt-[var(--ds-space-05x)] flex flex-wrap items-center gap-x-[var(--ds-space-1x)] gap-y-[var(--ds-space-025x)] ds-type-global-xs text-[var(--ds-text-neutral-lighter)]">
                            <MapPin className="h-[var(--ds-space-15x)] w-[var(--ds-space-15x)] shrink-0" />
                            {getResourceLocationPath(resource) ?? "Sin ubicación jerárquica"}
                            {resource.floor && <span className="text-[var(--ds-text-neutral-lighter)]">• {resource.floor}</span>}
                            {resource.capacity && resource.capacity > 1 && (
                              <>
                                <span className="text-[var(--ds-text-neutral-lighter)]">•</span>
                                <Users className="h-[var(--ds-space-15x)] w-[var(--ds-space-15x)] shrink-0" />
                                {resource.capacity} personas
                              </>
                            )}
                          </CardDescription>
                        </div>
                      </div>
                      {!hasImage && (resource.amenities as string[])?.length > 0 && (
                        <div className="flex flex-wrap justify-end gap-[var(--ds-space-05x)]">
                          {(resource.amenities as string[]).slice(0, 5).map((amenity) => (
                            <Badge
                              key={amenity}
                              className="rounded-[var(--ds-radius-s)] border-0 bg-[var(--ds-neutral-100)] ds-type-global-xxs text-[var(--ds-text-neutral-default)] hover:bg-[var(--ds-neutral-100)]"
                            >
                              {amenity}
                            </Badge>
                          ))}
                        </div>
                      )}
                    </div>
                    {hasImage && (resource.amenities as string[])?.length > 0 && (
                      <div className="mt-[var(--ds-space-1x)] flex flex-wrap gap-[var(--ds-space-05x)]">
                        {(resource.amenities as string[]).slice(0, 5).map((amenity) => (
                          <Badge
                            key={amenity}
                            className="rounded-[var(--ds-radius-s)] border-0 bg-[var(--ds-neutral-100)] ds-type-global-xxs text-[var(--ds-text-neutral-default)] hover:bg-[var(--ds-neutral-100)]"
                          >
                            {amenity}
                          </Badge>
                        ))}
                      </div>
                    )}
                  </CardHeader>
                  {advanceRestriction.disabled && advanceRestriction.message && (
                    <div className="mx-[var(--ds-space-3x)] mb-[var(--ds-space-2x)]">
                      <Alert className="rounded-[var(--ds-radius-m)] border-[var(--ds-warning-700)] bg-[var(--ds-warning-100)]">
                        <AlertDescription className="ds-type-global-xs text-[var(--ds-text-neutral-default)]">
                          {advanceRestriction.message}
                        </AlertDescription>
                      </Alert>
                    </div>
                  )}
                  <CardContent className="px-[var(--ds-space-3x)]">
                    <div className="flex flex-wrap gap-[var(--ds-space-05x)]">
                      {slotHeader.map((slot) => {
                        const stepMin = timeGranularityToMinutes(String(typeBooking.time_granularity))
                        const inWindow = slotStartIsInTypeWindow(slot, typeBooking)
                        const [slotHour, slotMin] = slot.split(":").map(Number)
                        const slotStart = setMinutes(setHours(selectedDate, slotHour), slotMin)
                        const disabledByAdvance =
                          !!advanceRestriction.minSlotStart &&
                          slotStart.getTime() < advanceRestriction.minSlotStart.getTime()
                        const available =
                          inWindow && isSlotAvailable(resource.id, slot, selectedDate, reservations, stepMin)
                        const slotDisabled =
                          advanceRestriction.disabled || !inWindow || !available || disabledByAdvance
                        const policyDisabledReason = advanceRestriction.disabled
                          ? (advanceRestriction.message ?? "Este recurso está bloqueado por política de antelación.")
                          : !inWindow
                            ? "Este horario está fuera de la ventana configurada para este tipo de recurso."
                            : disabledByAdvance && advanceRestriction.minSlotStart
                              ? `Este horario no cumple la antelación mínima. Puedes reservar desde las ${format(
                                  advanceRestriction.minSlotStart,
                                  "HH:mm",
                                )}.`
                              : undefined

                        const buttonClassName = cn(
                          "rounded-[var(--ds-radius-s)] border px-[var(--ds-space-1x)] py-[var(--ds-space-05x)] ds-type-global-xxs transition-colors",
                          available && !disabledByAdvance
                            ? "cursor-pointer border-[var(--ds-brand-400)] bg-[var(--ds-blueprimary-100)] text-[var(--ds-blueprimary-800)] hover:bg-[var(--ds-brand-400)] hover:text-[var(--background)]"
                            : "cursor-not-allowed border-[var(--ds-neutral-200)] bg-[var(--ds-neutral-100)] text-[var(--ds-text-neutral-lighter)]"
                        )

                        if (policyDisabledReason) {
                          return (
                            <PolicyDisabledTooltip key={slot} reason={policyDisabledReason}>
                              <button
                                type="button"
                                onClick={() => !slotDisabled && handleSlotClick(resource, slot)}
                                disabled={slotDisabled}
                                className={buttonClassName}
                              >
                                {slot}
                              </button>
                            </PolicyDisabledTooltip>
                          )
                        }

                        return (
                          <button
                            key={slot}
                            type="button"
                            onClick={() => !slotDisabled && handleSlotClick(resource, slot)}
                            disabled={slotDisabled}
                            className={buttonClassName}
                          >
                            {slot}
                          </button>
                        )
                      })}
                    </div>
                  </CardContent>
                </div>
                {hasImage && (
                  <div className="relative w-[min(calc(var(--ds-space-5x)*8),35%)] shrink-0 self-stretch overflow-hidden rounded-r-[var(--ds-radius-l)]">
                    <img
                      src={resourceImageUrl}
                      alt={resource.name}
                      className="h-full min-h-[calc(var(--ds-space-16x)+var(--ds-space-5x)+var(--ds-space-15x))] w-full object-cover"
                    />
                  </div>
                )}
              </Card>
            )
          })}

          {filteredResources.length === 0 && (
            <Card className="rounded-[var(--ds-radius-l)] border-[var(--ds-neutral-200)] bg-[var(--background)] py-[var(--ds-space-3x)] shadow-[var(--ds-shadow-4dp)]">
              <CardContent className="flex flex-col items-center justify-center py-[var(--ds-space-5x)] text-center">
                <Monitor className="mb-[var(--ds-space-2x)] h-[var(--ds-space-5x)] w-[var(--ds-space-5x)] text-[var(--ds-text-neutral-lighter)]" />
                <h3 className="ds-type-global-s ds-type-semibold text-[var(--ds-text-neutral-default)]">
                  No hay recursos disponibles
                </h3>
                <p className="mt-[var(--ds-space-05x)] ds-type-global-xs text-[var(--ds-text-neutral-lighter)]">
                  Prueba ajustando los filtros
                </p>
              </CardContent>
            </Card>
          )}
        </div>
      )}

      <ReservationDialog
        open={dialogOpen}
        onOpenChange={handleDialogClose}
        resource={selectedResource}
        date={selectedDate}
        initialTimeSlot={selectedTimeSlot}
        bookingFields={
          selectedResource
            ? normalizeResourceTypeBookingFields(
                selectedResource.resource_types as Partial<ResourceTypeBookingFields> | null | undefined,
              )
            : DEFAULT_BOOKING_FIELDS
        }
      />
    </div>
  )
}
