import {
  mdiCalendarClock,
  mdiCheckCircleOutline,
  mdiCreditCardCheckOutline,
  mdiDoorOpen,
  mdiHomeCity,
  mdiPlusCircleOutline,
} from '@mdi/js'
import axios from 'axios'
import Head from 'next/head'
import React, { ReactElement, useCallback, useEffect, useMemo, useState } from 'react'
import BaseButton from '../components/BaseButton'
import CardBox from '../components/CardBox'
import SectionMain from '../components/SectionMain'
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'
import { getPageTitle } from '../config'
import LayoutAuthenticated from '../layouts/Authenticated'

type RoomStatus = 'Available' | 'Occupied' | 'Dirty' | 'Cleaning' | 'Inspected' | 'Out of Service'
type ReservationStatus = 'Pending' | 'Confirmed' | 'Checked In' | 'Checked Out' | 'Cancelled' | 'No Show'
type DataMode = 'loading' | 'live' | 'demo'

type EntityRef = {
  id?: string
  name?: string
  label?: string
  first_name?: string
  last_name?: string
  email?: string
  phone?: string
  room_number?: string
  channel_type?: string
  base_rate?: number | string | null
  currency?: string
  default_tax_rate?: number | string | null
}

type RawRoom = {
  id: string
  room_number?: string
  floor?: string
  status?: string
  notes?: string
  active?: boolean
  hotel?: EntityRef | null
  room_type?: EntityRef | null
  hotelId?: string
  room_typeId?: string
}

type RawReservation = {
  id: string
  reservation_number?: string
  check_in_at?: string
  check_out_at?: string
  adults?: number | string | null
  children?: number | string | null
  status?: string
  total_amount?: number | string | null
  tax_amount?: number | string | null
  deposit_amount?: number | string | null
  special_requests?: string
  internal_notes?: string
  createdAt?: string
  guest?: EntityRef | null
  room?: RawRoom | null
  room_type?: EntityRef | null
  sales_channel?: EntityRef | null
  hotel?: EntityRef | null
  guestId?: string
  roomId?: string
  room_typeId?: string
  sales_channelId?: string
  hotelId?: string
}

type RawPayment = {
  id: string
  method?: string
  amount?: number | string | null
  status?: string
  paid_at?: string
  receipt_number?: string
  reservation?: EntityRef | null
  reservationId?: string
}

type RawHousekeepingTask = {
  id: string
  scheduled_for?: string
  started_at?: string
  completed_at?: string
  status?: string
  task_type?: string
  notes?: string
  room?: RawRoom | null
  roomId?: string
}

type RawMaintenanceTicket = {
  id: string
  category?: string
  priority?: string
  title?: string
  description?: string
  status?: string
  opened_at?: string
  closed_at?: string
  room?: RawRoom | null
  roomId?: string
}

type RawPricingRule = {
  id: string
  name?: string
  rule_type?: string
  adjustment_percent?: number | string | null
  adjustment_amount?: number | string | null
  min_occupancy_percent?: number | string | null
  max_occupancy_percent?: number | string | null
  min_days_before?: number | string | null
  max_days_before?: number | string | null
  applies_days_of_week?: string
  active?: boolean
  room_type?: EntityRef | null
}

type RawOtaConnection = {
  id: string
  provider?: string
  account_identifier?: string
  inventory_sync_enabled?: boolean
  rate_sync_enabled?: boolean
  last_sync_at?: string
  sync_status?: string
  sales_channel?: EntityRef | null
}

type RawSalesChannel = {
  id: string
  name?: string
  channel_type?: string
  active?: boolean
}

type Room = {
  id: string
  number: string
  type: string
  floor: string
  rate: number
  status: RoomStatus
  hotelId?: string
  roomTypeId?: string
  raw?: RawRoom
}

type Reservation = {
  id: string
  reservationNumber: string
  guestName: string
  email: string
  phone: string
  roomId: string
  roomTypeId?: string
  hotelId?: string
  guestId?: string
  salesChannelId?: string
  checkIn: string
  checkOut: string
  adults: number
  children: number
  source: string
  status: ReservationStatus
  totalAmount: number
  paidAmount: number
  createdAt: string
  raw?: RawReservation
}

type StripeCheckoutResponse = {
  id?: string
  url?: string
  status?: string
  payment_status?: string
}

type OtaSyncResult = {
  connection?: {
    id?: string
    provider?: string
    account_identifier?: string
    sync_status?: string
    last_sync_at?: string
  }
  inbound?: {
    received?: number
    created?: number
    updated?: number
    cancelled?: number
    skipped?: number
    errors?: string[]
  }
  outbound?: {
    rooms?: unknown[]
    inventory?: unknown[]
    rates?: unknown[]
  }
  count?: number
  ok?: number
  warnings?: number
  errors?: number
  results?: OtaSyncResult[]
  message?: string
  error?: string
}

type ReservationForm = {
  guestName: string
  email: string
  phone: string
  roomId: string
  checkIn: string
  checkOut: string
  adults: string
  children: string
  source: string
  nightlyRate: string
  weeklyRate: string
  deposit: string
}

type ApiListResponse<T> = {
  rows?: T[]
  count?: number
}

type PmsApiData = {
  rooms: RawRoom[]
  reservations: RawReservation[]
  payments: RawPayment[]
  housekeepingTasks: RawHousekeepingTask[]
  maintenanceTickets: RawMaintenanceTicket[]
  pricingRules: RawPricingRule[]
  otaConnections: RawOtaConnection[]
  salesChannels: RawSalesChannel[]
  hotels: EntityRef[]
}

const today = new Date()
const toIsoDate = (date: Date) => date.toISOString().slice(0, 10)
const toDateTimeValue = (date: string) => `${date}T15:00`
const addDays = (date: Date, days: number) => {
  const next = new Date(date)
  next.setDate(next.getDate() + days)
  return next
}

const dateLabel = (date: string) =>
  new Intl.DateTimeFormat('en', { month: 'short', day: 'numeric' }).format(new Date(`${date}T12:00:00`))

const dateTimeLabel = (date?: string) => {
  if (!date) return 'Never synced'

  const parsed = new Date(date)
  if (Number.isNaN(parsed.getTime())) return 'Never synced'

  return new Intl.DateTimeFormat('en', {
    month: 'short',
    day: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
  }).format(parsed)
}

const money = (amount: number) =>
  new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(amount)

const nightsBetween = (checkIn: string, checkOut: string) => {
  const start = new Date(`${checkIn}T12:00:00`).getTime()
  const end = new Date(`${checkOut}T12:00:00`).getTime()
  return Math.max(1, Math.round((end - start) / 86400000))
}

const parseAmount = (value: number | string | null | undefined) => {
  const parsed = Number(value || 0)
  return Number.isFinite(parsed) ? parsed : 0
}

const rateFormValues = (nightlyRate: number) => ({
  nightlyRate: String(nightlyRate),
  weeklyRate: String(nightlyRate * 7),
})

const rateAmount = (value: string, fallback: number) => {
  if (value.trim() === '') return fallback

  return Math.max(0, parseAmount(value))
}

const calculateStayQuote = (checkIn: string, checkOut: string, nightlyRateInput: string, weeklyRateInput: string, fallbackNightlyRate: number) => {
  const nights = nightsBetween(checkIn, checkOut)
  const nightlyRate = rateAmount(nightlyRateInput, fallbackNightlyRate)
  const weeklyRate = rateAmount(weeklyRateInput, nightlyRate * 7)
  const fullWeeks = Math.floor(nights / 7)
  const extraNights = nights % 7

  return {
    nights,
    nightlyRate,
    weeklyRate,
    fullWeeks,
    extraNights,
    total: fullWeeks * weeklyRate + extraNights * nightlyRate,
  }
}

const quoteBreakdownText = (quote: ReturnType<typeof calculateStayQuote>) => {
  if (quote.fullWeeks && quote.extraNights) {
    return `${quote.fullWeeks} week(s) × ${money(quote.weeklyRate)} + ${quote.extraNights} night(s) × ${money(quote.nightlyRate)}`
  }

  if (quote.fullWeeks) {
    return `${quote.fullWeeks} week(s) × ${money(quote.weeklyRate)}`
  }

  return `${quote.nights} night(s) × ${money(quote.nightlyRate)}`
}

const normalizeLabel = (value?: string | null) =>
  (value || '')
    .split('_')
    .filter(Boolean)
    .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
    .join(' ')

const normalizeDate = (value?: string, fallback = toIsoDate(today)) => {
  if (!value) return fallback
  const date = new Date(value)
  if (Number.isNaN(date.getTime())) return fallback
  return toIsoDate(date)
}

const balanceDue = (reservation: Reservation) => Math.max(reservation.totalAmount - reservation.paidAmount, 0)

const summarizeOtaSync = (result: OtaSyncResult) => {
  if (result.results) {
    return `${result.ok || 0} OTA syncs ok, ${result.warnings || 0} warnings, ${result.errors || 0} errors across ${result.count || 0} connections.`
  }

  const inbound = result.inbound
  const outbound = result.outbound

  return `Imported ${inbound?.created || 0} new, updated ${inbound?.updated || 0}, cancelled ${inbound?.cancelled || 0}, skipped ${inbound?.skipped || 0}; exported ${outbound?.inventory?.length || 0} availability rows and ${outbound?.rates?.length || 0} rate groups.`
}

const apiErrorMessage = (error: unknown) => {
  if (axios.isAxiosError(error)) {
    const data = error.response?.data

    if (typeof data === 'string') return data

    if (data && typeof data === 'object' && 'message' in data) {
      const message = (data as { message?: unknown }).message
      if (typeof message === 'string') return message
    }

    return error.message
  }

  if (error instanceof Error) return error.message

  return 'Unexpected PMS error.'
}

const initialRooms: Room[] = [
  { id: '101', number: '101', type: 'Standard King', floor: '1', rate: 145, status: 'Available' },
  { id: '102', number: '102', type: 'Standard Double', floor: '1', rate: 155, status: 'Dirty' },
  { id: '201', number: '201', type: 'Deluxe Ocean', floor: '2', rate: 225, status: 'Occupied' },
  { id: '202', number: '202', type: 'Deluxe Ocean', floor: '2', rate: 225, status: 'Available' },
  { id: '301', number: '301', type: 'Family Suite', floor: '3', rate: 310, status: 'Cleaning' },
  { id: '302', number: '302', type: 'Family Suite', floor: '3', rate: 310, status: 'Out of Service' },
  { id: '401', number: '401', type: 'Executive Suite', floor: '4', rate: 420, status: 'Available' },
  { id: '402', number: '402', type: 'Executive Suite', floor: '4', rate: 420, status: 'Available' },
]

const initialReservations: Reservation[] = [
  {
    id: 'res-1001',
    reservationNumber: 'HP-1001',
    guestName: 'Maya Chen',
    email: 'maya.chen@example.com',
    phone: '+1 415 555 0112',
    roomId: '201',
    checkIn: toIsoDate(addDays(today, -1)),
    checkOut: toIsoDate(addDays(today, 2)),
    adults: 2,
    children: 0,
    source: 'Website',
    status: 'Checked In',
    totalAmount: 675,
    paidAmount: 675,
    createdAt: toIsoDate(addDays(today, -8)),
  },
  {
    id: 'res-1002',
    reservationNumber: 'HP-1002',
    guestName: 'Jordan Smith',
    email: 'jordan.smith@example.com',
    phone: '+1 212 555 0188',
    roomId: '101',
    checkIn: toIsoDate(today),
    checkOut: toIsoDate(addDays(today, 1)),
    adults: 1,
    children: 0,
    source: 'Walk-in',
    status: 'Confirmed',
    totalAmount: 145,
    paidAmount: 0,
    createdAt: toIsoDate(today),
  },
  {
    id: 'res-1003',
    reservationNumber: 'HP-1003',
    guestName: 'Sofia Alvarez',
    email: 'sofia.alvarez@example.com',
    phone: '+1 305 555 0144',
    roomId: '401',
    checkIn: toIsoDate(addDays(today, 1)),
    checkOut: toIsoDate(addDays(today, 4)),
    adults: 2,
    children: 1,
    source: 'Booking.com',
    status: 'Confirmed',
    totalAmount: 1260,
    paidAmount: 420,
    createdAt: toIsoDate(addDays(today, -3)),
  },
]

const defaultForm: ReservationForm = {
  guestName: '',
  email: '',
  phone: '',
  roomId: initialRooms[0].id,
  checkIn: toIsoDate(today),
  checkOut: toIsoDate(addDays(today, 1)),
  adults: '1',
  children: '0',
  source: 'Walk-in',
  ...rateFormValues(initialRooms[0].rate),
  deposit: '0',
}

const emptyApiData: PmsApiData = {
  rooms: [],
  reservations: [],
  payments: [],
  housekeepingTasks: [],
  maintenanceTickets: [],
  pricingRules: [],
  otaConnections: [],
  salesChannels: [],
  hotels: [],
}

const statusClasses: Record<RoomStatus | ReservationStatus, string> = {
  Available: 'bg-emerald-50 text-emerald-700 ring-emerald-200',
  Occupied: 'bg-blue-50 text-blue-700 ring-blue-200',
  Dirty: 'bg-amber-50 text-amber-700 ring-amber-200',
  Cleaning: 'bg-cyan-50 text-cyan-700 ring-cyan-200',
  Inspected: 'bg-teal-50 text-teal-700 ring-teal-200',
  'Out of Service': 'bg-rose-50 text-rose-700 ring-rose-200',
  Pending: 'bg-slate-50 text-slate-700 ring-slate-200',
  Confirmed: 'bg-indigo-50 text-indigo-700 ring-indigo-200',
  'Checked In': 'bg-blue-50 text-blue-700 ring-blue-200',
  'Checked Out': 'bg-emerald-50 text-emerald-700 ring-emerald-200',
  Cancelled: 'bg-rose-50 text-rose-700 ring-rose-200',
  'No Show': 'bg-orange-50 text-orange-700 ring-orange-200',
}

const inputClassName =
  'mt-1 w-full rounded-xl border-slate-200 bg-white text-sm text-slate-800 shadow-sm focus:border-blue-500 focus:ring-blue-500 dark:border-dark-700 dark:bg-dark-800 dark:text-white'

const metricThemes = [
  'from-blue-600 to-cyan-500',
  'from-emerald-600 to-teal-400',
  'from-indigo-600 to-violet-500',
  'from-amber-500 to-orange-500',
]

const providerLabels: Record<string, string> = {
  booking_com: 'Booking.com',
  expedia: 'Expedia',
  airbnb: 'Airbnb',
  agoda: 'Agoda',
  other: 'Other OTA',
}

const roomStatusFromApi = (status?: string): RoomStatus => {
  switch (status) {
    case 'occupied':
      return 'Occupied'
    case 'dirty':
      return 'Dirty'
    case 'cleaning':
      return 'Cleaning'
    case 'inspected':
      return 'Inspected'
    case 'out_of_service':
      return 'Out of Service'
    default:
      return 'Available'
  }
}

const roomStatusToApi = (status: RoomStatus) => {
  switch (status) {
    case 'Occupied':
      return 'occupied'
    case 'Dirty':
      return 'dirty'
    case 'Cleaning':
      return 'cleaning'
    case 'Inspected':
      return 'inspected'
    case 'Out of Service':
      return 'out_of_service'
    default:
      return 'available'
  }
}

const reservationStatusFromApi = (status?: string): ReservationStatus => {
  switch (status) {
    case 'confirmed':
      return 'Confirmed'
    case 'checked_in':
      return 'Checked In'
    case 'checked_out':
      return 'Checked Out'
    case 'cancelled':
      return 'Cancelled'
    case 'no_show':
      return 'No Show'
    default:
      return 'Pending'
  }
}

const reservationStatusToApi = (status: ReservationStatus) => {
  switch (status) {
    case 'Confirmed':
      return 'confirmed'
    case 'Checked In':
      return 'checked_in'
    case 'Checked Out':
      return 'checked_out'
    case 'Cancelled':
      return 'cancelled'
    case 'No Show':
      return 'no_show'
    default:
      return 'pending'
  }
}

const sourceFromReservation = (reservation: RawReservation) => {
  if (reservation.sales_channel?.name) return reservation.sales_channel.name
  if (reservation.sales_channel?.channel_type) return normalizeLabel(reservation.sales_channel.channel_type)
  return 'Direct'
}

const guestNameFromReservation = (reservation: RawReservation) => {
  const firstName = reservation.guest?.first_name || ''
  const lastName = reservation.guest?.last_name || ''
  const fullName = `${firstName} ${lastName}`.trim()
  return fullName || `Guest ${reservation.reservation_number || reservation.id.slice(0, 8)}`
}

const splitGuestName = (guestName: string) => {
  const parts = guestName.trim().split(/\s+/).filter(Boolean)
  const firstName = parts.shift() || 'Guest'
  const lastName = parts.join(' ') || 'Walk-in'
  return { firstName, lastName }
}

const listRows = async <T,>(endpoint: string) => {
  const response = await axios.get<ApiListResponse<T>>(endpoint, { params: { limit: 200, page: 0 } })
  return Array.isArray(response.data.rows) ? response.data.rows : []
}

const mapRooms = (rawRooms: RawRoom[]) =>
  rawRooms.map((room, index) => ({
    id: room.id,
    number: room.room_number || `${index + 1}`,
    type: room.room_type?.name || 'Room',
    floor: room.floor || '—',
    rate: parseAmount(room.room_type?.base_rate) || initialRooms[index % initialRooms.length]?.rate || 150,
    status: roomStatusFromApi(room.status),
    hotelId: room.hotel?.id || room.hotelId,
    roomTypeId: room.room_type?.id || room.room_typeId,
    raw: room,
  }))

const paymentReservationId = (payment: RawPayment) => payment.reservation?.id || payment.reservationId || ''

const mapReservations = (rawReservations: RawReservation[], rooms: Room[], payments: RawPayment[]) =>
  rawReservations.map((reservation, index) => {
    const roomId = reservation.room?.id || reservation.roomId || rooms[index % Math.max(rooms.length, 1)]?.id || ''
    const room = rooms.find((item) => item.id === roomId)
    const checkIn = normalizeDate(reservation.check_in_at)
    const checkOut = normalizeDate(reservation.check_out_at, toIsoDate(addDays(today, 1)))
    const fallbackTotal = room ? room.rate * nightsBetween(checkIn, checkOut) : 0
    const paidFromPayments = payments
      .filter((payment) => paymentReservationId(payment) === reservation.id && ['captured', 'authorized'].includes(payment.status || ''))
      .reduce((sum, payment) => sum + parseAmount(payment.amount), 0)

    return {
      id: reservation.id,
      reservationNumber: reservation.reservation_number || `HP-${1000 + index}`,
      guestName: guestNameFromReservation(reservation),
      email: reservation.guest?.email || '',
      phone: reservation.guest?.phone || '',
      roomId,
      roomTypeId: reservation.room_type?.id || reservation.room_typeId || room?.roomTypeId,
      hotelId: reservation.hotel?.id || reservation.hotelId || room?.hotelId,
      guestId: reservation.guest?.id || reservation.guestId,
      salesChannelId: reservation.sales_channel?.id || reservation.sales_channelId,
      checkIn,
      checkOut,
      adults: Number(reservation.adults || 1),
      children: Number(reservation.children || 0),
      source: sourceFromReservation(reservation),
      status: reservationStatusFromApi(reservation.status),
      totalAmount: parseAmount(reservation.total_amount) || fallbackTotal,
      paidAmount: paidFromPayments || parseAmount(reservation.deposit_amount),
      createdAt: normalizeDate(reservation.createdAt),
      raw: reservation,
    }
  })

const FrontDesk = () => {
  const [rooms, setRooms] = useState<Room[]>(initialRooms)
  const [reservations, setReservations] = useState<Reservation[]>(initialReservations)
  const [apiData, setApiData] = useState<PmsApiData>(emptyApiData)
  const [dataMode, setDataMode] = useState<DataMode>('loading')
  const [form, setForm] = useState<ReservationForm>(defaultForm)
  const [selectedReservationId, setSelectedReservationId] = useState(initialReservations[0].id)
  const [successMessage, setSuccessMessage] = useState('')
  const [errorMessage, setErrorMessage] = useState('')
  const [isCreatingCheckout, setIsCreatingCheckout] = useState(false)
  const [isSyncing, setIsSyncing] = useState(true)
  const [otaSyncingId, setOtaSyncingId] = useState<string | null>(null)
  const [otaSyncResult, setOtaSyncResult] = useState<OtaSyncResult | null>(null)

  const loadPmsData = useCallback(async () => {
    if (typeof window !== 'undefined' && !window.localStorage.getItem('token')) {
      setIsSyncing(false)
      setDataMode('demo')
      return
    }

    setIsSyncing(true)
    setDataMode((mode) => (mode === 'demo' ? 'demo' : 'loading'))

    try {
      const [
        rawRooms,
        rawReservations,
        rawPayments,
        rawHousekeepingTasks,
        rawMaintenanceTickets,
        rawPricingRules,
        rawOtaConnections,
        rawSalesChannels,
        rawHotels,
      ] = await Promise.all([
        listRows<RawRoom>('rooms'),
        listRows<RawReservation>('reservations'),
        listRows<RawPayment>('payments'),
        listRows<RawHousekeepingTask>('housekeeping_tasks'),
        listRows<RawMaintenanceTicket>('maintenance_tickets'),
        listRows<RawPricingRule>('dynamic_pricing_rules'),
        listRows<RawOtaConnection>('ota_connections'),
        listRows<RawSalesChannel>('sales_channels'),
        listRows<EntityRef>('hotels'),
      ])

      const mappedRooms = rawRooms.length ? mapRooms(rawRooms) : initialRooms
      const mappedReservations = rawReservations.length ? mapReservations(rawReservations, mappedRooms, rawPayments) : initialReservations

      setApiData({
        rooms: rawRooms,
        reservations: rawReservations,
        payments: rawPayments,
        housekeepingTasks: rawHousekeepingTasks,
        maintenanceTickets: rawMaintenanceTickets,
        pricingRules: rawPricingRules,
        otaConnections: rawOtaConnections,
        salesChannels: rawSalesChannels,
        hotels: rawHotels,
      })
      setRooms(mappedRooms)
      setReservations(mappedReservations)
      setSelectedReservationId((currentId) => mappedReservations.find((reservation) => reservation.id === currentId)?.id || mappedReservations[0]?.id || '')
      setForm((currentForm) => {
        if (mappedRooms.find((room) => room.id === currentForm.roomId)) return currentForm

        const defaultRoom = mappedRooms[0]

        return {
          ...currentForm,
          roomId: defaultRoom?.id || currentForm.roomId,
          ...rateFormValues(defaultRoom?.rate || 0),
        }
      })
      setDataMode(rawRooms.length || rawReservations.length ? 'live' : 'demo')
      setSuccessMessage(rawRooms.length || rawReservations.length ? 'Live PMS data synced from your database.' : 'No live room/reservation rows yet, so demo data is displayed until you create records.')
      setErrorMessage('')
    } catch (error) {
      console.error('Failed to sync PMS cockpit data', error)
      setDataMode('demo')
      setErrorMessage(`Live PMS sync failed: ${apiErrorMessage(error)}. Demo data remains visible.`)
    } finally {
      setIsSyncing(false)
    }
  }, [])

  useEffect(() => {
    loadPmsData()
  }, [loadPmsData])

  const calendarDays = useMemo(() => Array.from({ length: 7 }, (_, index) => toIsoDate(addDays(today, index))), [])

  const selectedReservation = reservations.find((reservation) => reservation.id === selectedReservationId)
  const selectedRoom = selectedReservation
    ? rooms.find((room) => room.id === selectedReservation.roomId)
    : undefined
  const selectedBalanceDue = selectedReservation ? balanceDue(selectedReservation) : 0

  const activePricingRules = useMemo(() => apiData.pricingRules.filter((rule) => rule.active), [apiData.pricingRules])
  const activeOtaConnections = useMemo(
    () => apiData.otaConnections.filter((connection) => connection.sync_status !== 'disabled'),
    [apiData.otaConnections]
  )
  const openMaintenanceTickets = useMemo(
    () => apiData.maintenanceTickets.filter((ticket) => ticket.status !== 'closed'),
    [apiData.maintenanceTickets]
  )

  const roomStatusCounts = useMemo(
    () => ({
      available: rooms.filter((room) => ['Available', 'Inspected'].includes(room.status)).length,
      occupied: rooms.filter((room) => room.status === 'Occupied').length,
      dirty: rooms.filter((room) => room.status === 'Dirty').length,
      cleaning: rooms.filter((room) => room.status === 'Cleaning').length,
      outOfService: rooms.filter((room) => room.status === 'Out of Service').length,
    }),
    [rooms]
  )

  const upcomingReservations = useMemo(
    () =>
      reservations
        .filter((reservation) => ['Confirmed', 'Pending'].includes(reservation.status))
        .sort((a, b) => a.checkIn.localeCompare(b.checkIn)),
    [reservations]
  )

  const inHouseReservations = useMemo(
    () => reservations.filter((reservation) => reservation.status === 'Checked In'),
    [reservations]
  )

  const revenueToday = useMemo(
    () =>
      reservations
        .filter((reservation) => reservation.checkIn <= toIsoDate(today) && reservation.checkOut >= toIsoDate(today))
        .reduce((sum, reservation) => sum + reservation.totalAmount, 0),
    [reservations]
  )

  const paymentsCaptured = useMemo(
    () =>
      dataMode === 'live'
        ? apiData.payments
            .filter((payment) => ['captured', 'authorized'].includes(payment.status || ''))
            .reduce((sum, payment) => sum + parseAmount(payment.amount), 0)
        : reservations.reduce((sum, reservation) => sum + reservation.paidAmount, 0),
    [apiData.payments, dataMode, reservations]
  )

  const occupancyRate = rooms.length ? Math.round((roomStatusCounts.occupied / rooms.length) * 100) : 0
  const readinessScore = rooms.length
    ? Math.round(((roomStatusCounts.available + roomStatusCounts.cleaning * 0.5) / rooms.length) * 100)
    : 0

  const arrivalsToday = reservations.filter((reservation) => reservation.checkIn === toIsoDate(today)).length
  const departuresToday = reservations.filter((reservation) => reservation.checkOut === toIsoDate(today)).length

  const selectedRoomRate = rooms.find((room) => room.id === form.roomId)?.rate || 0
  const stayQuote = calculateStayQuote(form.checkIn, form.checkOut, form.nightlyRate, form.weeklyRate, selectedRoomRate)
  const quotedTotal = stayQuote.total
  const rateBreakdown = quoteBreakdownText(stayQuote)

  const hotelName = apiData.hotels[0]?.name || rooms.find((room) => room.hotelId)?.raw?.hotel?.name || 'HotelPilot PMS'

  const salesChannelOptions = useMemo(() => {
    const liveChannels = apiData.salesChannels.map((channel) => channel.name || normalizeLabel(channel.channel_type) || 'Direct')
    return Array.from(new Set(['Walk-in', 'Website', 'Booking.com', 'Expedia', 'Phone', ...liveChannels, ...reservations.map((reservation) => reservation.source)]))
  }, [apiData.salesChannels, reservations])

  const channelCards = useMemo(() => {
    const counts = reservations.reduce<Record<string, number>>((acc, reservation) => {
      acc[reservation.source] = (acc[reservation.source] || 0) + 1
      return acc
    }, {})
    const colors = ['bg-emerald-500', 'bg-blue-500', 'bg-indigo-500', 'bg-amber-500', 'bg-rose-500']
    const total = Math.max(reservations.length, 1)
    const entries = Object.entries(counts).length ? Object.entries(counts) : [['Website', 0]]

    return entries.map(([source, bookings], index) => ({
      source,
      bookings,
      share: Math.round((bookings / total) * 100),
      health: apiData.otaConnections.find((connection) => providerLabels[connection.provider || ''] === source)?.sync_status || (source === 'Walk-in' ? 'Front desk' : 'Live mix'),
      color: colors[index % colors.length],
    }))
  }, [apiData.otaConnections, reservations])

  const automationTiles = useMemo(
    () => [
      {
        title: 'Direct booking engine',
        detail: `${roomStatusCounts.available} rooms ready for web and direct reservations.`,
        value: dataMode === 'live' ? 'Live DB' : 'Demo',
      },
      {
        title: 'OTA channel manager',
        detail: `${activeOtaConnections.length} OTA connections loaded with inventory/rate sync status.`,
        value: `${activeOtaConnections.length} synced`,
      },
      {
        title: 'Guest messaging',
        detail: `${arrivalsToday} arrivals can receive automated pre-arrival instructions.`,
        value: arrivalsToday ? 'Queue' : 'Clear',
      },
      {
        title: 'Night audit reports',
        detail: `${money(paymentsCaptured)} captured/authorized payments are available for audit rollup.`,
        value: '02:00',
      },
    ],
    [activeOtaConnections.length, arrivalsToday, dataMode, paymentsCaptured, roomStatusCounts.available]
  )

  const handleRoomSelect = (roomId: string) => {
    const nextRoom = rooms.find((room) => room.id === roomId)

    setForm({
      ...form,
      roomId,
      ...rateFormValues(nextRoom?.rate || 0),
    })
  }

  const resetReservationForm = () => {
    const defaultRoom = rooms[0] || initialRooms[0]

    setForm({
      ...defaultForm,
      roomId: defaultRoom?.id || defaultForm.roomId,
      ...rateFormValues(defaultRoom?.rate || initialRooms[0].rate),
    })
  }

  const updateReservationStatus = async (id: string, status: ReservationStatus) => {
    setErrorMessage('')
    const previousReservations = reservations
    const reservation = reservations.find((item) => item.id === id)

    setReservations((current) => current.map((item) => (item.id === id ? { ...item, status } : item)))

    if (dataMode !== 'live' || !reservation?.raw) {
      setSuccessMessage(`Reservation marked as ${status}.`)
      return
    }

    try {
      await axios.put(`reservations/${id}`, { id, data: { status: reservationStatusToApi(status) } })
      await loadPmsData()
      setSuccessMessage(`Reservation ${reservation.reservationNumber} saved as ${status}.`)
    } catch (error) {
      console.error('Failed to update reservation status', error)
      setReservations(previousReservations)
      setErrorMessage(apiErrorMessage(error))
    }
  }

  const updateRoomStatus = async (id: string, status: RoomStatus) => {
    setErrorMessage('')
    const previousRooms = rooms
    const room = rooms.find((item) => item.id === id)

    setRooms((current) => current.map((item) => (item.id === id ? { ...item, status } : item)))

    if (dataMode !== 'live' || !room?.raw) {
      setSuccessMessage(`Room ${room?.number || id} marked as ${status}.`)
      return
    }

    try {
      await axios.put(`rooms/${id}`, { id, data: { status: roomStatusToApi(status) } })
      await loadPmsData()
      setSuccessMessage(`Room ${room.number} saved as ${status}.`)
    } catch (error) {
      console.error('Failed to update room status', error)
      setRooms(previousRooms)
      setErrorMessage(apiErrorMessage(error))
    }
  }

  const handleCreateReservation = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault()
    setErrorMessage('')

    const room = rooms.find((item) => item.id === form.roomId)
    if (!room) {
      setErrorMessage('Choose an available room before creating a reservation.')
      return
    }

    const deposit = parseAmount(form.deposit)
    const { firstName, lastName } = splitGuestName(form.guestName)
    const selectedSalesChannel = apiData.salesChannels.find(
      (channel) => channel.name === form.source || normalizeLabel(channel.channel_type) === form.source
    )
    const hotelId = room.hotelId || apiData.hotels[0]?.id

    if (dataMode === 'live') {
      try {
        await axios.post('guests', {
          data: {
            first_name: firstName,
            last_name: lastName,
            email: form.email || null,
            phone: form.phone || null,
            hotel: hotelId || null,
          },
        })

        const guests = await listRows<EntityRef>('guests')
        const createdGuest = guests.find(
          (guest) => guest.first_name === firstName && guest.last_name === lastName && (!form.email || guest.email === form.email)
        ) || guests[0]

        const reservationNumber = `HP-${Date.now().toString().slice(-6)}`
        await axios.post('reservations', {
          data: {
            reservation_number: reservationNumber,
            guest: createdGuest?.id || null,
            room: room.id,
            room_type: room.roomTypeId || null,
            hotel: hotelId || null,
            sales_channel: selectedSalesChannel?.id || null,
            check_in_at: toDateTimeValue(form.checkIn),
            check_out_at: toDateTimeValue(form.checkOut),
            adults: Number(form.adults || 1),
            children: Number(form.children || 0),
            status: 'confirmed',
            total_amount: quotedTotal,
            deposit_amount: deposit,
            internal_notes: `Created from Front Desk cockpit via ${form.source}. Rate: ${rateBreakdown}. Nightly rate ${money(stayQuote.nightlyRate)}; weekly 7-night rate ${money(stayQuote.weeklyRate)}; total ${money(quotedTotal)}.`,
          },
        })

        resetReservationForm()
        await loadPmsData()
        setSuccessMessage(`Live reservation ${reservationNumber} created and saved to the database.`)
        return
      } catch (error) {
        console.error('Failed to create live reservation', error)
        setErrorMessage(apiErrorMessage(error))
        return
      }
    }

    const newReservation: Reservation = {
      id: `res-${Date.now()}`,
      reservationNumber: `HP-${1000 + reservations.length + 1}`,
      guestName: form.guestName || 'Walk-in Guest',
      email: form.email,
      phone: form.phone,
      roomId: room.id,
      checkIn: form.checkIn,
      checkOut: form.checkOut,
      adults: Number(form.adults || 1),
      children: Number(form.children || 0),
      source: form.source,
      status: 'Confirmed',
      totalAmount: quotedTotal,
      paidAmount: deposit,
      createdAt: toIsoDate(today),
    }

    setReservations((current) => [newReservation, ...current])
    setSelectedReservationId(newReservation.id)
    setRooms((current) => current.map((item) => (item.id === room.id ? { ...item, status: 'Occupied' } : item)))
    resetReservationForm()
    setSuccessMessage(`Demo reservation ${newReservation.reservationNumber} created with ${rateBreakdown}. Use live entity records to persist to Postgres.`)
  }

  const handleCreateCheckoutSession = async () => {
    if (!selectedReservation || !selectedRoom || selectedBalanceDue <= 0) return

    setIsCreatingCheckout(true)
    setErrorMessage('')
    setSuccessMessage('')

    try {
      const response = await axios.post<StripeCheckoutResponse>('/stripe/create-checkout-session', {
        amount: selectedBalanceDue,
        currency: 'usd',
        reservationId: selectedReservation.id,
        reservationNumber: selectedReservation.reservationNumber,
        guestName: selectedReservation.guestName,
        description: `${hotelName} reservation ${selectedReservation.reservationNumber} · Room ${selectedRoom.number}`,
      })

      if (response.data?.url) {
        window.location.href = response.data.url
        return
      }

      setErrorMessage('Stripe did not return a checkout URL.')
    } catch (error) {
      console.error('Failed to create Stripe Checkout session', error)
      setErrorMessage(apiErrorMessage(error))
    } finally {
      setIsCreatingCheckout(false)
    }
  }

  const handleSyncOtaConnection = async (connection: RawOtaConnection) => {
    if (!connection.id) return

    const providerName = providerLabels[connection.provider || ''] || normalizeLabel(connection.provider) || 'OTA'
    setOtaSyncingId(connection.id)
    setErrorMessage('')
    setSuccessMessage('')

    try {
      const response = await axios.put<OtaSyncResult>(`ota_connections/${connection.id}/sync`, {
        data: { mode: 'full', days: 30 },
      })
      setOtaSyncResult(response.data)
      await loadPmsData()
      setSuccessMessage(`${providerName} sync complete. ${summarizeOtaSync(response.data)}`)
    } catch (error) {
      console.error('Failed to sync OTA connection', error)
      setErrorMessage(`OTA sync failed: ${apiErrorMessage(error)}`)
    } finally {
      setOtaSyncingId(null)
    }
  }

  const handleSyncAllOtaConnections = async () => {
    setOtaSyncingId('all')
    setErrorMessage('')
    setSuccessMessage('')

    try {
      const response = await axios.put<OtaSyncResult>('ota_connections/sync-all', {
        data: { mode: 'full', days: 30 },
      })
      setOtaSyncResult(response.data)
      await loadPmsData()
      setSuccessMessage(`OTA sync-all complete. ${summarizeOtaSync(response.data)}`)
    } catch (error) {
      console.error('Failed to sync all OTA connections', error)
      setErrorMessage(`OTA sync-all failed: ${apiErrorMessage(error)}`)
    } finally {
      setOtaSyncingId(null)
    }
  }

  const metrics = [
    { label: 'Live occupancy', value: `${occupancyRate}%`, detail: `${roomStatusCounts.occupied}/${rooms.length} rooms occupied` },
    { label: 'Revenue today', value: money(revenueToday), detail: `${money(paymentsCaptured)} payments captured` },
    { label: 'Arrivals today', value: arrivalsToday.toString(), detail: `${departuresToday} departures` },
    { label: 'Ops readiness', value: `${readinessScore}%`, detail: `${roomStatusCounts.dirty} dirty · ${openMaintenanceTickets.length} open tickets` },
  ]

  const forecastLift = activePricingRules.reduce((sum, rule) => sum + parseAmount(rule.adjustment_percent), 0)
  const leadingRule = activePricingRules[0]
  const pricingCoachCards = [
    { label: 'Active rules', value: activePricingRules.length.toString(), detail: leadingRule?.name || 'Create rules in Dynamic Pricing Rules' },
    { label: 'Suggested lift', value: `${forecastLift >= 0 ? '+' : ''}${forecastLift || 0}%`, detail: leadingRule ? normalizeLabel(leadingRule.rule_type) : 'Based on live rule settings' },
    { label: 'Pickup pressure', value: occupancyRate > 70 ? 'High' : occupancyRate > 40 ? 'Moderate' : 'Low', detail: `${occupancyRate}% current occupancy` },
  ]

  const housekeepingStats = [
    { label: 'Available', value: roomStatusCounts.available, color: 'text-emerald-600' },
    { label: 'Dirty', value: roomStatusCounts.dirty, color: 'text-amber-600' },
    { label: 'Cleaning', value: roomStatusCounts.cleaning, color: 'text-cyan-600' },
    { label: 'Out of service', value: roomStatusCounts.outOfService, color: 'text-rose-600' },
  ]

  return (
    <>
      <Head>
        <title>{getPageTitle('Front Desk')}</title>
      </Head>
      <SectionMain>
        <SectionTitleLineWithButton icon={mdiHomeCity} title="PMS Command Center" main>
          <BaseButton color="info" icon={mdiCalendarClock} label={isSyncing ? 'Syncing…' : 'Refresh live data'} small disabled={isSyncing} onClick={loadPmsData} />
        </SectionTitleLineWithButton>

        <div className="mb-6 overflow-hidden rounded-[2rem] bg-gradient-to-br from-slate-950 via-blue-950 to-cyan-900 p-6 text-white shadow-2xl shadow-blue-950/20 lg:p-8">
          <div className="grid gap-8 xl:grid-cols-[1.1fr_0.9fr] xl:items-center">
            <div>
              <div className="mb-5 flex flex-wrap items-center gap-3">
                <span className="rounded-full bg-white/10 px-3 py-1 text-xs font-bold uppercase tracking-[0.2em] text-cyan-100 ring-1 ring-white/20">
                  {dataMode === 'live' ? 'Live database cockpit' : dataMode === 'loading' ? 'Loading live PMS' : 'Demo fallback'}
                </span>
                <span className="rounded-full bg-emerald-400/20 px-3 py-1 text-xs font-semibold text-emerald-100 ring-1 ring-emerald-300/30">
                  {hotelName}
                </span>
              </div>
              <h1 className="max-w-4xl text-3xl font-black tracking-tight md:text-5xl">
                Sirvoy-style front desk, Smart PMS-style automation, connected to HotelPilot data.
              </h1>
              <p className="mt-4 max-w-3xl text-sm leading-7 text-cyan-50/80 md:text-base">
                Reservations, room readiness, payments, dynamic pricing rules, OTA connections, housekeeping, and maintenance now come from the generated PMS APIs instead of static display cards.
              </p>
              <div className="mt-6 grid gap-3 sm:grid-cols-4">
                {[
                  ['Reservations', reservations.length],
                  ['Rooms', rooms.length],
                  ['OTA links', activeOtaConnections.length],
                  ['Rules', activePricingRules.length],
                ].map(([label, value]) => (
                  <div key={label} className="rounded-2xl bg-white/10 p-4 ring-1 ring-white/15 backdrop-blur">
                    <p className="text-2xl font-black">{value}</p>
                    <p className="text-xs font-semibold uppercase tracking-[0.16em] text-cyan-100/75">{label}</p>
                  </div>
                ))}
              </div>
            </div>
            <div className="rounded-[1.7rem] bg-white/10 p-5 ring-1 ring-white/15 backdrop-blur">
              <div className="mb-4 flex items-center justify-between gap-3">
                <div>
                  <p className="text-xs font-black uppercase tracking-[0.18em] text-cyan-100/75">Today command stack</p>
                  <h2 className="text-2xl font-black">{dateLabel(toIsoDate(today))}</h2>
                </div>
                <span className="rounded-2xl bg-cyan-300 px-4 py-2 text-sm font-black text-slate-950">{occupancyRate}% full</span>
              </div>
              <div className="space-y-3">
                {upcomingReservations.slice(0, 4).map((reservation) => (
                  <button
                    key={reservation.id}
                    type="button"
                    className="flex w-full items-center justify-between rounded-2xl bg-white/10 p-3 text-left ring-1 ring-white/10 transition hover:bg-white/15"
                    onClick={() => setSelectedReservationId(reservation.id)}
                  >
                    <span>
                      <span className="block font-black">{reservation.guestName}</span>
                      <span className="text-xs text-cyan-50/70">{reservation.reservationNumber} · {dateLabel(reservation.checkIn)} · {reservation.source}</span>
                    </span>
                    <span className="rounded-full bg-white/15 px-2 py-1 text-xs font-bold">Room {rooms.find((room) => room.id === reservation.roomId)?.number || 'TBD'}</span>
                  </button>
                ))}
                {!upcomingReservations.length && <p className="rounded-2xl bg-white/10 p-3 text-sm text-cyan-50/75">No arrivals are waiting in the current filtered data.</p>}
              </div>
            </div>
          </div>
        </div>

        {(successMessage || errorMessage) && (
          <div className="mb-6 grid gap-3">
            {successMessage && <div className="rounded-2xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm font-semibold text-emerald-700">{successMessage}</div>}
            {errorMessage && <div className="rounded-2xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm font-semibold text-rose-700">{errorMessage}</div>}
          </div>
        )}

        <div className="grid gap-5 md:grid-cols-2 xl:grid-cols-4">
          {metrics.map((metric, index) => (
            <CardBox key={metric.label} className={`border-0 bg-gradient-to-br ${metricThemes[index]} text-white shadow-xl shadow-slate-900/10`}>
              <div className="flex items-start justify-between gap-4">
                <div>
                  <p className="text-xs font-bold uppercase tracking-[0.2em] text-white/70">{metric.label}</p>
                  <p className="mt-3 text-3xl font-black">{metric.value}</p>
                  <p className="mt-2 text-sm text-white/75">{metric.detail}</p>
                </div>
                <span className="rounded-2xl bg-white/15 p-3 text-white"><span className="sr-only">metric</span></span>
              </div>
            </CardBox>
          ))}
        </div>

        <div className="mt-6 grid gap-6 xl:grid-cols-[1.25fr_0.75fr]">
          <CardBox className="border-0 bg-white shadow-sm ring-1 ring-slate-100 dark:bg-dark-900 dark:ring-dark-700">
            <div className="mb-5 flex flex-wrap items-center justify-between gap-4">
              <div>
                <p className="text-xs font-black uppercase tracking-[0.18em] text-blue-500">Live PMS calendar</p>
                <h3 className="text-2xl font-black text-slate-950 dark:text-white">Room availability grid</h3>
                <p className="text-sm text-slate-500 dark:text-slate-300">Reservations and room readiness are rendered from live `/rooms` and `/reservations` API rows when available.</p>
              </div>
              <div className="flex flex-wrap gap-2 text-xs font-semibold">
                {Object.entries(roomStatusCounts).map(([key, value]) => <span key={key} className="rounded-full bg-slate-100 px-3 py-1 text-slate-600 dark:bg-dark-800 dark:text-slate-200">{normalizeLabel(key)}: {value}</span>)}
              </div>
            </div>
            <div className="overflow-x-auto">
              <div className="min-w-[760px] rounded-3xl border border-slate-100 dark:border-dark-700">
                <div className="grid grid-cols-[120px_repeat(7,minmax(90px,1fr))] border-b border-slate-100 bg-slate-50 text-xs font-black uppercase tracking-[0.14em] text-slate-400 dark:border-dark-700 dark:bg-dark-800">
                  <div className="p-3">Room</div>
                  {calendarDays.map((day) => <div key={day} className="border-l border-slate-100 p-3 text-center dark:border-dark-700">{dateLabel(day)}</div>)}
                </div>
                {rooms.map((room) => (
                  <div key={room.id} className="grid grid-cols-[120px_repeat(7,minmax(90px,1fr))] border-b border-slate-100 last:border-b-0 dark:border-dark-700">
                    <div className="p-3">
                      <p className="font-black text-slate-950 dark:text-white">{room.number}</p>
                      <p className="text-xs text-slate-400">{room.type}</p>
                    </div>
                    {calendarDays.map((day) => {
                      const booking = reservations.find((reservation) => reservation.roomId === room.id && reservation.checkIn <= day && reservation.checkOut > day && !['Cancelled', 'No Show'].includes(reservation.status))
                      return (
                        <button
                          key={`${room.id}-${day}`}
                          type="button"
                          className={`min-h-[74px] border-l border-slate-100 p-2 text-left transition dark:border-dark-700 ${booking ? 'bg-blue-50 hover:bg-blue-100 dark:bg-blue-950/30' : 'hover:bg-slate-50 dark:hover:bg-dark-800'}`}
                          onClick={() => booking && setSelectedReservationId(booking.id)}
                        >
                          {booking ? (
                            <>
                              <span className="block truncate text-xs font-black text-blue-800 dark:text-blue-200">{booking.guestName}</span>
                              <span className="mt-1 block text-[11px] text-blue-500">{booking.status}</span>
                            </>
                          ) : (
                            <span className={`rounded-full px-2 py-1 text-[11px] ring-1 ${statusClasses[room.status]}`}>{room.status}</span>
                          )}
                        </button>
                      )
                    })}
                  </div>
                ))}
              </div>
            </div>
          </CardBox>

          <CardBox className="border-0 bg-white shadow-sm ring-1 ring-slate-100 dark:bg-dark-900 dark:ring-dark-700">
            <div className="mb-5 flex items-center gap-3">
              <span className="rounded-2xl bg-blue-50 p-3 text-blue-700"><span className="text-xl">+</span></span>
              <div>
                <p className="text-xs font-black uppercase tracking-[0.18em] text-blue-500">Walk-in / direct booking</p>
                <h3 className="text-xl font-black text-slate-950 dark:text-white">Create reservation</h3>
              </div>
            </div>
            <form className="space-y-4" onSubmit={handleCreateReservation}>
              <div>
                <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Guest name</label>
                <input className={inputClassName} value={form.guestName} onChange={(event) => setForm({ ...form, guestName: event.target.value })} placeholder="Alex Morgan" required />
              </div>
              <div className="grid gap-3 sm:grid-cols-2">
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Email</label>
                  <input className={inputClassName} type="email" value={form.email} onChange={(event) => setForm({ ...form, email: event.target.value })} placeholder="guest@example.com" />
                </div>
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Phone</label>
                  <input className={inputClassName} value={form.phone} onChange={(event) => setForm({ ...form, phone: event.target.value })} placeholder="+1 555 0100" />
                </div>
              </div>
              <div className="grid gap-3 sm:grid-cols-2">
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Room</label>
                  <select className={inputClassName} value={form.roomId} onChange={(event) => handleRoomSelect(event.target.value)}>
                    {rooms.map((room) => <option key={room.id} value={room.id}>Room {room.number} · {room.type} · {money(room.rate)}</option>)}
                  </select>
                </div>
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Source</label>
                  <select className={inputClassName} value={form.source} onChange={(event) => setForm({ ...form, source: event.target.value })}>
                    {salesChannelOptions.map((source) => <option key={source} value={source}>{source}</option>)}
                  </select>
                </div>
              </div>
              <div className="grid gap-3 sm:grid-cols-2">
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Check-in</label>
                  <input className={inputClassName} type="date" value={form.checkIn} onChange={(event) => setForm({ ...form, checkIn: event.target.value })} />
                </div>
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Check-out</label>
                  <input className={inputClassName} type="date" value={form.checkOut} onChange={(event) => setForm({ ...form, checkOut: event.target.value })} />
                </div>
              </div>
              <div className="grid gap-3 sm:grid-cols-3">
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Adults</label>
                  <input className={inputClassName} type="number" min="1" value={form.adults} onChange={(event) => setForm({ ...form, adults: event.target.value })} />
                </div>
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Children</label>
                  <input className={inputClassName} type="number" min="0" value={form.children} onChange={(event) => setForm({ ...form, children: event.target.value })} />
                </div>
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Deposit</label>
                  <input className={inputClassName} type="number" min="0" value={form.deposit} onChange={(event) => setForm({ ...form, deposit: event.target.value })} />
                </div>
              </div>
              <div className="grid gap-3 sm:grid-cols-2">
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Nightly rate</label>
                  <input className={inputClassName} type="number" min="0" step="0.01" value={form.nightlyRate} onChange={(event) => setForm({ ...form, nightlyRate: event.target.value })} />
                </div>
                <div>
                  <label className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">Weekly rate / 7 nights</label>
                  <input className={inputClassName} type="number" min="0" step="0.01" value={form.weeklyRate} onChange={(event) => setForm({ ...form, weeklyRate: event.target.value })} />
                </div>
              </div>
              <div className="rounded-2xl bg-slate-50 p-4 dark:bg-dark-800">
                <div className="flex items-center justify-between">
                  <span className="text-sm font-semibold text-slate-500">Quote</span>
                  <span className="text-2xl font-black text-slate-950 dark:text-white">{money(quotedTotal)}</span>
                </div>
                <p className="mt-1 text-xs text-slate-400">{rateBreakdown}</p>
                <p className="mt-1 text-[11px] text-slate-400">Room default is {money(selectedRoomRate)} nightly. Weekly rate applies to every full 7-night block.</p>
              </div>
              <BaseButton type="submit" color="success" icon={mdiPlusCircleOutline} label={dataMode === 'live' ? 'Create live booking' : 'Create demo booking'} className="w-full" />
            </form>
          </CardBox>
        </div>

        <div className="mt-6 grid gap-6 xl:grid-cols-[0.8fr_1.2fr]">
          <CardBox className="border-0 bg-white shadow-sm ring-1 ring-slate-100 dark:bg-dark-900 dark:ring-dark-700">
            <div className="mb-5 flex items-center gap-3">
              <span className="rounded-2xl bg-indigo-50 p-3 text-indigo-700"><span className="text-xl">⇄</span></span>
              <div>
                <p className="text-xs font-black uppercase tracking-[0.18em] text-indigo-500">Front desk queue</p>
                <h3 className="text-xl font-black text-slate-950 dark:text-white">Arrivals and in-house stays</h3>
              </div>
            </div>
            <div className="space-y-3">
              {[...inHouseReservations, ...upcomingReservations].slice(0, 8).map((reservation) => (
                <button
                  key={reservation.id}
                  type="button"
                  className={`w-full rounded-3xl border p-4 text-left transition ${selectedReservationId === reservation.id ? 'border-blue-300 bg-blue-50 dark:border-blue-700 dark:bg-blue-950/30' : 'border-slate-100 bg-white hover:bg-slate-50 dark:border-dark-700 dark:bg-dark-900 dark:hover:bg-dark-800'}`}
                  onClick={() => setSelectedReservationId(reservation.id)}
                >
                  <div className="flex items-start justify-between gap-3">
                    <div>
                      <p className="font-black text-slate-950 dark:text-white">{reservation.guestName}</p>
                      <p className="text-xs text-slate-500">{reservation.reservationNumber} · {dateLabel(reservation.checkIn)}–{dateLabel(reservation.checkOut)}</p>
                    </div>
                    <span className={`rounded-full px-2 py-1 text-[11px] ring-1 ${statusClasses[reservation.status]}`}>{reservation.status}</span>
                  </div>
                </button>
              ))}
              {!reservations.length && <p className="rounded-2xl bg-slate-50 p-4 text-sm text-slate-500 dark:bg-dark-800 dark:text-slate-300">No reservation rows found.</p>}
            </div>
          </CardBox>

          <CardBox className="border-0 bg-white shadow-sm ring-1 ring-slate-100 dark:bg-dark-900 dark:ring-dark-700">
            {selectedReservation ? (
              <>
                <div className="mb-5 flex flex-wrap items-start justify-between gap-4">
                  <div>
                    <p className="text-xs font-black uppercase tracking-[0.18em] text-blue-500">Stay detail</p>
                    <h3 className="text-2xl font-black text-slate-950 dark:text-white">{selectedReservation.guestName}</h3>
                    <p className="text-sm text-slate-500 dark:text-slate-300">{selectedReservation.reservationNumber} · {selectedReservation.source}</p>
                  </div>
                  <span className={`rounded-full px-3 py-1 text-xs font-bold ring-1 ${statusClasses[selectedReservation.status]}`}>{selectedReservation.status}</span>
                </div>
                <div className="grid gap-4 md:grid-cols-3">
                  {[
                    ['Room', selectedRoom ? `${selectedRoom.number} · ${selectedRoom.type}` : 'Unassigned'],
                    ['Stay', `${dateLabel(selectedReservation.checkIn)} → ${dateLabel(selectedReservation.checkOut)}`],
                    ['Guests', `${selectedReservation.adults} adults · ${selectedReservation.children} children`],
                    ['Total', money(selectedReservation.totalAmount)],
                    ['Paid', money(selectedReservation.paidAmount)],
                    ['Balance', money(selectedBalanceDue)],
                  ].map(([label, value]) => (
                    <div key={label} className="rounded-3xl bg-slate-50 p-4 dark:bg-dark-800">
                      <p className="text-xs font-black uppercase tracking-[0.16em] text-slate-400">{label}</p>
                      <p className="mt-2 font-black text-slate-950 dark:text-white">{value}</p>
                    </div>
                  ))}
                </div>
                <div className="mt-5 flex flex-wrap gap-3">
                  <BaseButton color="info" icon={mdiDoorOpen} label="Check in" disabled={selectedReservation.status === 'Checked In'} onClick={() => updateReservationStatus(selectedReservation.id, 'Checked In')} />
                  <BaseButton color="success" icon={mdiCheckCircleOutline} label="Check out" disabled={selectedReservation.status === 'Checked Out'} onClick={() => updateReservationStatus(selectedReservation.id, 'Checked Out')} />
                  <BaseButton color="danger" label="Cancel" disabled={['Cancelled', 'Checked Out'].includes(selectedReservation.status)} onClick={() => updateReservationStatus(selectedReservation.id, 'Cancelled')} />
                </div>
                <div className="mt-6 rounded-3xl border border-blue-100 bg-blue-50 p-5 dark:border-blue-900/50 dark:bg-blue-950/20">
                  <div className="flex flex-wrap items-center justify-between gap-4">
                    <div>
                      <p className="text-xs font-black uppercase tracking-[0.18em] text-blue-500">Stripe Checkout</p>
                      <h4 className="text-lg font-black text-slate-950 dark:text-white">Collect balance due</h4>
                      <p className="text-sm text-slate-500 dark:text-slate-300">Creates a protected Stripe Checkout Session through `/api/stripe/create-checkout-session`.</p>
                    </div>
                    <BaseButton color="info" icon={mdiCreditCardCheckOutline} label={selectedBalanceDue > 0 ? `Collect ${money(selectedBalanceDue)}` : 'Paid'} disabled={selectedBalanceDue <= 0 || isCreatingCheckout} onClick={handleCreateCheckoutSession} />
                  </div>
                </div>
              </>
            ) : (
              <p className="text-sm text-slate-500">Select a reservation to view stay details.</p>
            )}
          </CardBox>
        </div>

        <div className="mt-6 grid gap-6 xl:grid-cols-[0.9fr_1.1fr]">
          <CardBox className="border-0 bg-white shadow-sm ring-1 ring-slate-100 dark:bg-dark-900 dark:ring-dark-700">
            <div className="mb-5 flex items-center gap-3">
              <span className="rounded-2xl bg-emerald-50 p-3 text-emerald-700"><span className="text-xl">AI</span></span>
              <div>
                <p className="text-xs font-black uppercase tracking-[0.18em] text-emerald-500">Smart pricing coach</p>
                <h3 className="text-xl font-black text-slate-950 dark:text-white">Dynamic pricing rules</h3>
                <p className="text-sm text-slate-500 dark:text-slate-300">Live rules from the `dynamic_pricing_rules` entity drive these recommendations.</p>
              </div>
            </div>
            <div className="grid gap-3 sm:grid-cols-3">
              {pricingCoachCards.map((item) => (
                <div key={item.label} className="rounded-3xl bg-slate-50 p-4 dark:bg-dark-800">
                  <p className="text-2xl font-black text-slate-950 dark:text-white">{item.value}</p>
                  <p className="text-xs font-black uppercase tracking-[0.16em] text-slate-400">{item.label}</p>
                  <p className="mt-2 text-xs text-slate-500 dark:text-slate-300">{item.detail}</p>
                </div>
              ))}
            </div>
            <div className="mt-4 space-y-3">
              {(activePricingRules.length ? activePricingRules : apiData.pricingRules).slice(0, 4).map((rule) => (
                <div key={rule.id} className="rounded-3xl border border-slate-100 p-4 dark:border-dark-700">
                  <div className="flex items-center justify-between gap-3">
                    <div>
                      <p className="font-black text-slate-950 dark:text-white">{rule.name || 'Pricing rule'}</p>
                      <p className="text-xs text-slate-500">{normalizeLabel(rule.rule_type)} · {rule.room_type?.name || 'All room types'}</p>
                    </div>
                    <span className="rounded-full bg-emerald-50 px-3 py-1 text-xs font-black text-emerald-700 ring-1 ring-emerald-200">{parseAmount(rule.adjustment_percent) ? `${parseAmount(rule.adjustment_percent)}%` : money(parseAmount(rule.adjustment_amount))}</span>
                  </div>
                </div>
              ))}
              {!apiData.pricingRules.length && <p className="rounded-2xl bg-slate-50 p-4 text-sm text-slate-500 dark:bg-dark-800 dark:text-slate-300">No dynamic pricing rules found yet.</p>}
            </div>
          </CardBox>

          <CardBox className="border-0 bg-white shadow-sm ring-1 ring-slate-100 dark:bg-dark-900 dark:ring-dark-700">
            <div className="mb-5 flex items-center gap-3">
              <span className="rounded-2xl bg-amber-50 p-3 text-amber-700"><span className="text-xl">🧹</span></span>
              <div>
                <p className="text-xs font-black uppercase tracking-[0.18em] text-amber-500">Housekeeping + maintenance</p>
                <h3 className="text-xl font-black text-slate-950 dark:text-white">Readiness board</h3>
                <p className="text-sm text-slate-500 dark:text-slate-300">Room state plus live housekeeping tasks and open maintenance tickets.</p>
              </div>
            </div>
            <div className="mb-5 grid gap-3 sm:grid-cols-4">
              {housekeepingStats.map((item) => (
                <div key={item.label} className="rounded-3xl bg-slate-50 p-4 dark:bg-dark-800">
                  <p className={`text-2xl font-black ${item.color}`}>{item.value}</p>
                  <p className="text-xs font-semibold text-slate-400">{item.label}</p>
                </div>
              ))}
            </div>
            <div className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
              {rooms.slice(0, 8).map((room) => (
                <div key={room.id} className="rounded-3xl border border-slate-100 bg-white p-4 shadow-sm dark:border-dark-700 dark:bg-dark-900">
                  <div className="mb-3 flex items-start justify-between gap-3">
                    <div>
                      <p className="text-lg font-black text-slate-950 dark:text-white">Room {room.number}</p>
                      <p className="text-xs text-slate-500">Floor {room.floor} · {room.type}</p>
                    </div>
                    <span className={`rounded-full px-2 py-1 text-[11px] ring-1 ${statusClasses[room.status]}`}>{room.status}</span>
                  </div>
                  <div className="mb-3 h-2 overflow-hidden rounded-full bg-slate-100 dark:bg-dark-800">
                    <div className={`h-full ${['Available', 'Inspected'].includes(room.status) ? 'w-full bg-emerald-500' : room.status === 'Cleaning' ? 'w-2/3 bg-cyan-500' : room.status === 'Dirty' ? 'w-1/3 bg-amber-500' : room.status === 'Occupied' ? 'w-full bg-blue-500' : 'w-1/4 bg-rose-500'}`} />
                  </div>
                  <div className="grid grid-cols-2 gap-2">
                    <BaseButton small color="info" label="Start" disabled={!['Dirty', 'Cleaning'].includes(room.status)} onClick={() => updateRoomStatus(room.id, 'Cleaning')} />
                    <BaseButton small color="success" label="Inspect" disabled={!['Dirty', 'Cleaning'].includes(room.status)} onClick={() => updateRoomStatus(room.id, 'Available')} />
                  </div>
                </div>
              ))}
            </div>
            <div className="mt-5 grid gap-3 md:grid-cols-2">
              <div className="rounded-3xl bg-slate-50 p-4 dark:bg-dark-800">
                <p className="mb-3 text-xs font-black uppercase tracking-[0.16em] text-slate-400">Today tasks</p>
                {apiData.housekeepingTasks.slice(0, 4).map((task) => (
                  <p key={task.id} className="mb-2 text-sm text-slate-600 dark:text-slate-300">{normalizeLabel(task.task_type)} · Room {task.room?.room_number || rooms.find((room) => room.id === task.roomId)?.number || 'TBD'} · {normalizeLabel(task.status)}</p>
                ))}
                {!apiData.housekeepingTasks.length && <p className="text-sm text-slate-500">No housekeeping task rows found.</p>}
              </div>
              <div className="rounded-3xl bg-slate-50 p-4 dark:bg-dark-800">
                <p className="mb-3 text-xs font-black uppercase tracking-[0.16em] text-slate-400">Open tickets</p>
                {openMaintenanceTickets.slice(0, 4).map((ticket) => (
                  <p key={ticket.id} className="mb-2 text-sm text-slate-600 dark:text-slate-300">{ticket.title || normalizeLabel(ticket.category)} · {normalizeLabel(ticket.priority)} · {normalizeLabel(ticket.status)}</p>
                ))}
                {!openMaintenanceTickets.length && <p className="text-sm text-slate-500">No open maintenance tickets.</p>}
              </div>
            </div>
          </CardBox>
        </div>

        <div className="mt-6 grid gap-6 xl:grid-cols-2">
          <CardBox className="border-0 bg-white shadow-sm ring-1 ring-slate-100 dark:bg-dark-900 dark:ring-dark-700">
            <div className="mb-5 flex items-center gap-3">
              <span className="rounded-2xl bg-violet-50 p-3 text-violet-700"><span className="text-xl">⚡</span></span>
              <div>
                <p className="text-xs font-black uppercase tracking-[0.18em] text-violet-500">Automation layer</p>
                <h3 className="text-xl font-black text-slate-950 dark:text-white">All-in-one PMS modules</h3>
                <p className="text-sm text-slate-500 dark:text-slate-300">Cards now reflect live inventory, OTA, messaging queue, and payment audit data.</p>
              </div>
            </div>
            <div className="grid gap-3 sm:grid-cols-2">
              {automationTiles.map((tile) => (
                <div key={tile.title} className="rounded-3xl border border-slate-100 bg-slate-50 p-4 dark:border-dark-700 dark:bg-dark-800">
                  <div className="mb-3 flex items-center justify-between gap-3">
                    <p className="font-black text-slate-950 dark:text-white">{tile.title}</p>
                    <span className="rounded-full bg-white px-3 py-1 text-xs font-black text-slate-600 shadow-sm dark:bg-dark-900 dark:text-slate-200">{tile.value}</span>
                  </div>
                  <p className="text-sm leading-6 text-slate-500 dark:text-slate-300">{tile.detail}</p>
                </div>
              ))}
            </div>
          </CardBox>

          <CardBox className="border-0 bg-white shadow-sm ring-1 ring-slate-100 dark:bg-dark-900 dark:ring-dark-700">
            <div className="mb-5 flex flex-wrap items-start justify-between gap-3">
              <div className="flex items-center gap-3">
                <span className="rounded-2xl bg-blue-50 p-3 text-blue-700"><span className="text-xl">%</span></span>
                <div>
                  <p className="text-xs font-black uppercase tracking-[0.18em] text-blue-500">Channels + distribution</p>
                  <h3 className="text-xl font-black text-slate-950 dark:text-white">Booking mix and OTA sync</h3>
                  <p className="text-sm text-slate-500 dark:text-slate-300">Import OTA reservations, export 30-day inventory/rates, and update connection health.</p>
                </div>
              </div>
              <BaseButton
                color="info"
                outline
                small
                label={otaSyncingId === 'all' ? 'Syncing OTAs…' : 'Sync all OTAs'}
                disabled={!activeOtaConnections.length || Boolean(otaSyncingId)}
                onClick={handleSyncAllOtaConnections}
              />
            </div>
            <div className="space-y-4">
              {channelCards.map((channel) => (
                <div key={channel.source}>
                  <div className="mb-2 flex items-center justify-between gap-3 text-sm">
                    <div>
                      <p className="font-black text-slate-950 dark:text-white">{channel.source}</p>
                      <p className="text-xs text-slate-400">{channel.bookings} bookings · {normalizeLabel(channel.health)}</p>
                    </div>
                    <span className="font-black text-slate-900 dark:text-white">{channel.share}%</span>
                  </div>
                  <div className="h-3 overflow-hidden rounded-full bg-slate-100 dark:bg-dark-800">
                    <div className={`h-full rounded-full ${channel.color}`} style={{ width: `${Math.max(channel.share, 4)}%` }} />
                  </div>
                </div>
              ))}
            </div>
            <div className="mt-5 rounded-3xl bg-slate-50 p-4 dark:bg-dark-800">
              <p className="mb-3 text-xs font-black uppercase tracking-[0.16em] text-slate-400">OTA sync connections</p>
              {apiData.otaConnections.slice(0, 4).map((connection) => {
                const providerName = providerLabels[connection.provider || ''] || normalizeLabel(connection.provider) || 'OTA'
                const isConnectionSyncing = otaSyncingId === connection.id

                return (
                  <div key={connection.id} className="mb-3 rounded-2xl bg-white p-3 text-sm shadow-sm last:mb-0 dark:bg-dark-900">
                    <div className="flex items-start justify-between gap-3">
                      <div>
                        <p className="font-black text-slate-800 dark:text-slate-100">{providerName}</p>
                        <p className="text-xs text-slate-400">{connection.account_identifier || 'No account ID'} · {dateTimeLabel(connection.last_sync_at)}</p>
                        <p className="mt-1 text-xs text-slate-500 dark:text-slate-300">Inventory {connection.inventory_sync_enabled ? 'on' : 'off'} · Rates {connection.rate_sync_enabled ? 'on' : 'off'}</p>
                      </div>
                      <span className="rounded-full bg-slate-50 px-2 py-1 text-xs font-black text-slate-500 shadow-sm dark:bg-dark-800">{normalizeLabel(connection.sync_status || 'pending')}</span>
                    </div>
                    <div className="mt-3 flex flex-wrap gap-2">
                      <BaseButton
                        color="info"
                        small
                        label={isConnectionSyncing ? 'Syncing…' : 'Sync now'}
                        disabled={Boolean(otaSyncingId)}
                        onClick={() => handleSyncOtaConnection(connection)}
                      />
                      <BaseButton href={`/ota_connections/ota_connections-view/?id=${connection.id}`} color="whiteDark" small label="Open setup" />
                    </div>
                  </div>
                )
              })}
              {!apiData.otaConnections.length && (
                <div className="rounded-2xl bg-white p-3 text-sm text-slate-500 shadow-sm dark:bg-dark-900 dark:text-slate-300">
                  No OTA connection rows found yet. Create one in OTA Connections, enable inventory/rate sync, then return here to run the channel sync.
                </div>
              )}
              {otaSyncResult && (
                <div className="mt-4 rounded-2xl border border-blue-100 bg-blue-50 p-3 text-sm text-blue-800 dark:border-blue-900/60 dark:bg-blue-950/30 dark:text-blue-100">
                  <p className="font-black">Last OTA sync result</p>
                  <p className="mt-1">{summarizeOtaSync(otaSyncResult)}</p>
                  {otaSyncResult.inbound?.errors?.slice(0, 2).map((message) => (
                    <p key={message} className="mt-1 text-xs text-amber-700 dark:text-amber-200">Warning: {message}</p>
                  ))}
                </div>
              )}
            </div>
          </CardBox>
        </div>
      </SectionMain>
    </>
  )
}

FrontDesk.getLayout = function getLayout(page: ReactElement) {
  return <LayoutAuthenticated>{page}</LayoutAuthenticated>
}

export default FrontDesk
