import React, { useState, useMemo } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { Link } from 'react-router-dom'
import Plot from 'react-plotly.js'
import { X } from 'lucide-react'
import api from '../api'

// Format Date as YYYY-MM-DD using local time (avoids UTC/DST shift from toISOString)
const fmtDate = (d: Date) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`

// Types
interface CategoryInfo {
  category_id: string
  category_name: string
  room_count: number
}

interface TariffInfo {
  name: string
  description?: string
  rate: number | null
  average_nightly?: number
  available: boolean
  message: string
  sort_order?: number
  min_stay?: number | null
  available_for_min_stay?: boolean | null  // True if available when queried with min_stay nights
}

interface OccupancyInfo {
  occupied: number
  available: number
  maintenance: number
}

interface DateRateInfo {
  rate_gross: number | null
  rate_net: number | null
  tariffs: TariffInfo[]
  tariff_count: number
  occupancy?: OccupancyInfo
  valid_from?: string | null
}

interface RateMatrixData {
  categories: CategoryInfo[]
  dates: string[]
  matrix: Record<string, Record<string, DateRateInfo>>
  date_last_updated?: Record<string, string | null>
  date_last_changed?: Record<string, string | null>
}

// Helper functions
const formatDateShort = (dateStr: string): string => {
  const date = new Date(dateStr + 'T00:00:00')
  return date.toLocaleDateString('en-GB', { day: 'numeric' })
}

const formatDayOfWeek = (dateStr: string): string => {
  const date = new Date(dateStr + 'T00:00:00')
  return date.toLocaleDateString('en-GB', { weekday: 'short' })
}

const formatLastUpdated = (isoStr: string | null | undefined): string => {
  if (!isoStr) return ''
  const d = new Date(isoStr)
  const now = new Date()
  const isToday = d.toDateString() === now.toDateString()
  return isToday
    ? d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })
    : d.toLocaleDateString('en-GB', { day: '2-digit', month: 'short' }) + ' ' + d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })
}

const isWeekend = (dateStr: string): boolean => {
  const date = new Date(dateStr + 'T00:00:00')
  const day = date.getDay()
  return day === 0 || day === 6
}

const todayStr = fmtDate(new Date())
const isPast = (dateStr: string): boolean => dateStr < todayStr

const formatCurrency = (value: number | null): string => {
  if (value === null || value === undefined) return '-'
  return new Intl.NumberFormat('en-GB', {
    style: 'currency',
    currency: 'GBP',
    minimumFractionDigits: 0,
    maximumFractionDigits: 0,
  }).format(value)
}

// Inline style helpers (replacing theme utilities)
const mergeStyles = (...styles: React.CSSProperties[]): React.CSSProperties =>
  Object.assign({}, ...styles)

const buttonStyle = (variant: 'primary' | 'secondary' | 'outline', size?: 'small'): React.CSSProperties => {
  const base: React.CSSProperties = {
    border: 'none',
    borderRadius: '6px',
    cursor: 'pointer',
    fontWeight: 500,
    padding: size === 'small' ? '4px 10px' : '8px 16px',
    fontSize: size === 'small' ? '13px' : '14px',
    lineHeight: 1.4,
    transition: 'all 0.15s',
  }
  if (variant === 'primary') return { ...base, background: 'var(--gold)', color: '#fff' }
  if (variant === 'secondary') return { ...base, background: 'var(--navy)', color: '#fff' }
  // outline
  return { ...base, background: 'transparent', color: 'var(--text-dark)', border: '1px solid var(--card-border)' }
}

const badgeStyle = (variant: 'success' | 'error' | 'warning' | 'info'): React.CSSProperties => {
  const map: Record<string, React.CSSProperties> = {
    success: { background: '#dcfce7', color: '#16a34a', padding: '2px 8px', borderRadius: '99px', fontSize: '12px', fontWeight: 600 },
    error:   { background: '#fee2e2', color: '#dc2626', padding: '2px 8px', borderRadius: '99px', fontSize: '12px', fontWeight: 600 },
    warning: { background: '#fef3c7', color: '#d97706', padding: '2px 8px', borderRadius: '99px', fontSize: '12px', fontWeight: 600 },
    info:    { background: '#dbeafe', color: '#2563eb', padding: '2px 8px', borderRadius: '99px', fontSize: '12px', fontWeight: 600 },
  }
  return map[variant] || map.info
}

// Components
const MonthSelector: React.FC<{
  value: string
  onChange: (value: string) => void
}> = ({ value, onChange }) => {
  const handlePrevMonth = () => {
    const [year, month] = value.split('-').map(Number)
    const date = new Date(year, month - 2, 1)
    onChange(`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`)
  }

  const handleNextMonth = () => {
    const [year, month] = value.split('-').map(Number)
    const date = new Date(year, month, 1)
    onChange(`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`)
  }

  // Generate month options (current month + next 12 months)
  const monthOptions = useMemo(() => {
    const options: { value: string; label: string }[] = []
    const now = new Date()
    for (let i = 0; i < 13; i++) {
      const date = new Date(now.getFullYear(), now.getMonth() + i, 1)
      const monthValue = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`
      const label = date.toLocaleDateString('en-GB', { month: 'long', year: 'numeric' })
      options.push({ value: monthValue, label })
    }
    return options
  }, [])

  return (
    <div style={styles.monthSelector}>
      <button onClick={handlePrevMonth} style={buttonStyle('outline', 'small')}>
        &larr;
      </button>
      <select
        value={value}
        onChange={(e) => onChange(e.target.value)}
        style={styles.monthDropdown}
      >
        {monthOptions.map((opt) => (
          <option key={opt.value} value={opt.value}>
            {opt.label}
          </option>
        ))}
      </select>
      <button onClick={handleNextMonth} style={buttonStyle('outline', 'small')}>
        &rarr;
      </button>
    </div>
  )
}

// Helper to collect unique tariff names across all dates for a category, preserving Newbook order
const getAllTariffNames = (rateData: Record<string, DateRateInfo>, dates: string[]): string[] => {
  const tariffMap = new Map<string, number>()
  for (const dateStr of dates) {
    const data = rateData[dateStr]
    if (data?.tariffs) {
      for (const tariff of data.tariffs) {
        if (!tariffMap.has(tariff.name)) {
          tariffMap.set(tariff.name, tariff.sort_order ?? 999)
        }
      }
    }
  }
  return Array.from(tariffMap.entries())
    .sort((a, b) => a[1] - b[1])
    .map(([name]) => name)
}

// Helper to format scrape age
const formatScrapeAge = (isoStr: string | null): string => {
  if (!isoStr) return ''
  const diff = Date.now() - new Date(isoStr).getTime()
  const mins = Math.floor(diff / 60000)
  if (mins < 60) return `${mins}m ago`
  const hours = Math.floor(mins / 60)
  if (hours < 24) return `${hours}h ago`
  const days = Math.floor(hours / 24)
  return `${days}d ago`
}

interface BookingAvailabilityData {
  has_own_hotel: boolean
  dates_checked: number
  dates_available: number
  dates_sold_out: number
  dates_no_data: number
  latest_scrape: string | null
  dates: Record<string, { status: string; rate: number | null }>
}

interface HistoryTarget {
  categoryId: string
  categoryName: string
  date: string
}

const LoadingSpinner: React.FC = () => (
  <div style={styles.loading}>
    <div style={styles.spinner} />
    <span>Loading rate data...</span>
  </div>
)

const ErrorMessage: React.FC<{ message: string }> = ({ message }) => (
  <div style={styles.error}>
    <span style={styles.errorIcon}>!</span>
    {message}
  </div>
)

// Main Component
const Bookability: React.FC = () => {
  const queryClient = useQueryClient()
  const [selectedMonth, setSelectedMonth] = useState(() => {
    const today = new Date()
    return `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}`
  })
  const [refreshingDate, setRefreshingDate] = useState<string | null>(null)
  const [history, setHistory] = useState<HistoryTarget | null>(null)

  // Calculate date range from selected month
  const { fromDate, toDate } = useMemo(() => {
    const [year, month] = selectedMonth.split('-').map(Number)
    const start = new Date(year, month - 1, 1)
    const end = new Date(year, month, 0) // Last day of month
    return {
      fromDate: fmtDate(start),
      toDate: fmtDate(end),
    }
  }, [selectedMonth])

  // Single-date refresh mutation
  const dateRefreshM = useMutation({
    mutationFn: async (d: string) => {
      setRefreshingDate(d)
      const res = await api.post(`/bookability/refresh-date/${d}`)
      return res.data
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['rate-matrix'] })
      setRefreshingDate(null)
    },
    onError: () => setRefreshingDate(null),
  })

  // Fetch Booking.com availability data
  const { data: bookingData } = useQuery<BookingAvailabilityData>({
    queryKey: ['booking-availability', fromDate, toDate],
    queryFn: async () => {
      const params = new URLSearchParams({ from_date: fromDate, to_date: toDate })
      const res = await api.get(`/competitors/booking-availability?${params}`)
      return res.data
    },
    staleTime: 5 * 60 * 1000,
  })

  // Fetch rate matrix data
  const { data, isLoading, error, refetch } = useQuery<RateMatrixData>({
    queryKey: ['rate-matrix', fromDate, toDate],
    queryFn: async () => {
      const params = new URLSearchParams({ from_date: fromDate, to_date: toDate })
      const res = await api.get(`/bookability/rate-matrix?${params}`)
      return res.data
    },
  })

  // Calculate summary stats - focus on unbookable dates (rooms available but no rates)
  const summary = useMemo(() => {
    if (!data) return null

    let totalDateCategories = 0
    let unbookableDateCategories = 0
    const unbookableIssues: { category: string; date: string; roomsLeft: number }[] = []

    for (const cat of data.categories) {
      const catData = data.matrix[cat.category_id]
      if (!catData) continue

      for (const dateStr of data.dates) {
        const dayData = catData[dateStr]
        if (!dayData) continue

        // Check if rooms are available (bookable = available - maintenance - occupied)
        const occ = dayData.occupancy
        const bookableRooms = occ ? occ.available - occ.maintenance : 0
        const roomsLeft = occ ? bookableRooms - occ.occupied : 0
        const hasRoomsAvailable = roomsLeft > 0

        // Only count dates where rooms are available
        if (hasRoomsAvailable) {
          totalDateCategories++

          // Check if ANY tariff is available for booking
          // A tariff is "bookable" if:
          // - available: true (single-night available), OR
          // - has min_stay > 1 AND available_for_min_stay: true (verified via multi-night query)
          const hasAnyAvailableRate = dayData.tariffs?.some(t => {
            if (t.available) return true
            // If has min_stay requirement and verified available for that stay length
            if (t.min_stay && t.min_stay > 1 && t.available_for_min_stay === true) return true
            return false
          }) ?? false

          if (!hasAnyAvailableRate && dayData.tariffs && dayData.tariffs.length > 0) {
            // Rooms available but no rates bookable - this is a problem!
            unbookableDateCategories++
            unbookableIssues.push({
              category: cat.category_name,
              date: dateStr,
              roomsLeft: roomsLeft,
            })
          }
        }
      }
    }

    return {
      totalDateCategories,
      unbookableDateCategories,
      unbookablePercent: totalDateCategories > 0
        ? ((unbookableDateCategories / totalDateCategories) * 100).toFixed(1)
        : '0',
      issues: unbookableIssues.slice(0, 10),
      hasMoreIssues: unbookableIssues.length > 10,
      totalIssues: unbookableIssues.length,
    }
  }, [data])

  return (
    <div style={styles.container}>
      {/* Header */}
      <div style={styles.header}>
        <div style={styles.headerTop}>
          <div>
            <h1 style={styles.title}>Rate Availability</h1>
            <p style={styles.subtitle}>
              View tariff availability across all room categories
            </p>
          </div>
          <div style={styles.headerActions}>
            <MonthSelector value={selectedMonth} onChange={setSelectedMonth} />
            <button
              onClick={() => refetch()}
              style={buttonStyle('outline', 'small')}
              disabled={isLoading}
            >
              Refresh
            </button>
          </div>
        </div>

        {/* Summary Stats */}
        {summary && (
          <div style={styles.summaryBar}>
            <div style={styles.summaryItem}>
              <span style={styles.summaryValue}>{data?.categories.length || 0}</span>
              <span style={styles.summaryLabel}>Room Types</span>
            </div>
            <div style={styles.summaryItem}>
              <span style={styles.summaryValue}>{data?.dates.length || 0}</span>
              <span style={styles.summaryLabel}>Days</span>
            </div>
            <div style={styles.summaryItem}>
              <span style={mergeStyles(
                styles.summaryValue,
                summary.unbookableDateCategories > 0 ? { color: 'var(--danger)' } : { color: 'var(--success)' }
              )}>
                {summary.unbookableDateCategories}
              </span>
              <span style={styles.summaryLabel}>Unbookable</span>
            </div>
            <div style={styles.summaryItem}>
              <span style={badgeStyle(summary.unbookableDateCategories > 0 ? 'warning' : 'success')}>
                {summary.unbookablePercent}% blocked
              </span>
            </div>
          </div>
        )}
      </div>

      {/* Content */}
      <div style={styles.content}>
        {isLoading && <LoadingSpinner />}
        {error && <ErrorMessage message={(error as Error).message} />}
        {data && data.categories.length === 0 && (
          <div style={styles.noData}>
            No room categories configured. Please set up room categories in Settings.
          </div>
        )}
        {data && data.categories.length > 0 && (
          <div style={styles.unifiedCard}>
            <div style={styles.tableContainer}>
              <table style={styles.table}>
                <thead>
                  <tr>
                    <th style={mergeStyles(styles.th, styles.stickyCol, styles.stickyHeader)}>Tariff</th>
                    {data.dates.map(dateStr => (
                      <th
                        key={dateStr}
                        style={mergeStyles(
                          styles.th,
                          styles.dateHeader,
                          styles.stickyHeader,
                          isWeekend(dateStr) ? styles.weekendHeader : {},
                          isPast(dateStr) ? { opacity: 0.45 } : {}
                        )}
                      >
                        <div style={styles.dateHeaderContent}>
                          <span style={styles.dayOfWeek}>{formatDayOfWeek(dateStr)}</span>
                          <span style={styles.dayNum}>{formatDateShort(dateStr)}</span>
                          <button
                            onClick={() => dateRefreshM.mutate(dateStr)}
                            disabled={refreshingDate !== null}
                            style={mergeStyles(
                              styles.scrapeBtn,
                              refreshingDate === dateStr ? styles.scrapeBtnActive : {}
                            )}
                            title={`Refresh ${dateStr}`}
                          >
                            {refreshingDate === dateStr ? '...' : '↻'}
                          </button>
                          {data.date_last_updated?.[dateStr] && (
                            <span
                              style={styles.lastUpdated}
                              title={[
                                `Checked: ${new Date(data.date_last_updated[dateStr]!).toLocaleString('en-GB')}`,
                                data.date_last_changed?.[dateStr]
                                  ? `Changed: ${new Date(data.date_last_changed[dateStr]!).toLocaleString('en-GB')}`
                                  : null,
                              ].filter(Boolean).join('\n')}
                            >
                              {formatLastUpdated(data.date_last_updated[dateStr])}
                            </span>
                          )}
                        </div>
                      </th>
                    ))}
                  </tr>
                </thead>
                <tbody>
                  {data.categories.map(category => {
                    const rateData = data.matrix[category.category_id] || {}
                    const tariffNames = getAllTariffNames(rateData, data.dates)
                    return (
                      <React.Fragment key={category.category_id}>
                        {/* Category header row */}
                        <tr>
                          <td style={mergeStyles(styles.categoryHeaderRow, styles.stickyCol, { zIndex: 15, overflow: 'visible', textOverflow: 'clip', width: 'auto', minWidth: '160px' })}>
                            {category.category_name}
                            <span style={styles.roomCount}> ({category.room_count} rooms)</span>
                          </td>
                          {data.dates.map(dateStr => (
                            <td key={dateStr} style={mergeStyles(styles.categoryHeaderFill, isPast(dateStr) ? { opacity: 0.45 } : {})} />
                          ))}
                        </tr>
                        {/* Occupancy row */}
                        <tr>
                          <td style={mergeStyles(styles.td, styles.stickyCol, styles.occupancyLabel)}>
                            Occupancy
                          </td>
                          {data.dates.map(dateStr => {
                            const dayData = rateData[dateStr]
                            const occ = dayData?.occupancy
                            if (!occ) {
                              return (
                                <td
                                  key={dateStr}
                                  style={mergeStyles(
                                    styles.td,
                                    styles.occupancyCell,
                                    isWeekend(dateStr) ? styles.weekendCell : {},
                                    { cursor: 'pointer' },
                                    isPast(dateStr) ? { opacity: 0.45 } : {}
                                  )}
                                  title="Click for history"
                                  onClick={() => setHistory({ categoryId: category.category_id, categoryName: category.category_name, date: dateStr })}
                                >
                                  -
                                </td>
                              )
                            }
                            const bookableRooms = occ.available - occ.maintenance
                            const roomsLeft = bookableRooms - occ.occupied
                            const isFull = roomsLeft <= 0
                            const occPercent = bookableRooms > 0
                              ? Math.round((occ.occupied / bookableRooms) * 100)
                              : 100
                            const isHighOcc = occPercent >= 80 && !isFull
                            const hasOffline = occ.maintenance > 0
                            const getOccStyle = () => {
                              if (isFull) return styles.occupancyFull
                              if (isHighOcc) return styles.occupancyHigh
                              return styles.occupancyAvailable
                            }
                            return (
                              <td
                                key={dateStr}
                                style={mergeStyles(
                                  styles.td,
                                  styles.occupancyCell,
                                  isWeekend(dateStr) ? styles.weekendCell : {},
                                  getOccStyle(),
                                  { cursor: 'pointer' },
                                  isPast(dateStr) ? { opacity: 0.45 } : {}
                                )}
                                title={`${occ.occupied} of ${bookableRooms} bookable rooms occupied${hasOffline ? ` (${occ.maintenance} offline)` : ''} - ${roomsLeft} left · click for history`}
                                onClick={() => setHistory({ categoryId: category.category_id, categoryName: category.category_name, date: dateStr })}
                              >
                                <span style={styles.occupancyText}>
                                  {occ.occupied}/{occ.available}
                                  {hasOffline && <span style={styles.maintenanceBadge}>({occ.maintenance})</span>}
                                </span>
                              </td>
                            )
                          })}
                        </tr>
                        {/* Tariff rows */}
                        {tariffNames.length === 0 ? (
                          <tr>
                            <td
                              colSpan={data.dates.length + 1}
                              style={{ ...styles.td, color: 'var(--text-mid)', textAlign: 'center' }}
                            >
                              No rate data available for this period
                            </td>
                          </tr>
                        ) : (
                          tariffNames.map(tariffName => (
                            <tr key={tariffName}>
                              <td style={mergeStyles(styles.td, styles.stickyCol, styles.tariffNameCell)}>
                                {tariffName}
                              </td>
                              {data.dates.map(dateStr => {
                                const dayData = rateData[dateStr]
                                const tariff = dayData?.tariffs?.find(t => t.name === tariffName)
                                const occupancy = dayData?.occupancy
                                const noRoomsAvailable = occupancy &&
                                  (occupancy.available - occupancy.maintenance - occupancy.occupied) <= 0

                                if (!tariff) {
                                  return (
                                    <td
                                      key={dateStr}
                                      style={mergeStyles(
                                        styles.td,
                                        styles.tariffCell,
                                        isWeekend(dateStr) ? styles.weekendCell : {},
                                        noRoomsAvailable ? styles.cellNoRooms : styles.cellNoData,
                                        isPast(dateStr) ? { opacity: 0.45 } : {}
                                      )}
                                      title={noRoomsAvailable ? 'No rooms available · click for history' : 'Click for history'}
                                      onClick={() => setHistory({ categoryId: category.category_id, categoryName: category.category_name, date: dateStr })}
                                    >
                                      -
                                    </td>
                                  )
                                }

                                const isEffectivelyAvailable = tariff.available ||
                                  (tariff.min_stay && tariff.min_stay > 1 && tariff.available_for_min_stay === true)
                                const minStayBadge = isEffectivelyAvailable && !noRoomsAvailable && tariff.min_stay && tariff.min_stay > 1 ? (
                                  <span style={styles.minStayBadge} title={`Minimum ${tariff.min_stay} nights`}>
                                    {tariff.min_stay}
                                  </span>
                                ) : null
                                const getCellStyle = () => {
                                  if (noRoomsAvailable) return styles.cellNoRooms
                                  if (isEffectivelyAvailable) return styles.cellAvailable
                                  return styles.cellUnavailable
                                }
                                const getTooltip = () => {
                                  if (noRoomsAvailable) return `${tariffName}: No rooms available`
                                  if (isEffectivelyAvailable) {
                                    const minStayNote = tariff.min_stay && tariff.min_stay > 1 ? ` (Min ${tariff.min_stay} nights)` : ''
                                    return `${tariffName}: ${formatCurrency(tariff.rate)}${minStayNote}`
                                  }
                                  return `${tariffName}: ${tariff.message || 'Not available'}`
                                }

                                return (
                                  <td
                                    key={dateStr}
                                    style={mergeStyles(
                                      styles.td,
                                      styles.tariffCell,
                                      isWeekend(dateStr) ? styles.weekendCell : {},
                                      getCellStyle(),
                                      !isEffectivelyAvailable && !noRoomsAvailable ? { textDecoration: 'line-through' } : {},
                                      isPast(dateStr) ? { opacity: 0.45 } : {}
                                    )}
                                    title={`${getTooltip()} · click for history`}
                                    onClick={() => setHistory({ categoryId: category.category_id, categoryName: category.category_name, date: dateStr })}
                                  >
                                    <span style={styles.cellContent}>
                                      {tariff.rate !== null ? formatCurrency(tariff.rate) : (isEffectivelyAvailable ? 'Y' : 'N')}
                                      {minStayBadge}
                                    </span>
                                  </td>
                                )
                              })}
                            </tr>
                          ))
                        )}
                      </React.Fragment>
                    )
                  })}
                  {/* Booking.com section */}
                  {bookingData && bookingData.has_own_hotel && (
                    <React.Fragment>
                      <tr>
                        <td style={mergeStyles(styles.categoryHeaderRow, styles.stickyCol, { zIndex: 15, overflow: 'visible', textOverflow: 'clip', width: 'auto', minWidth: '160px' })}>
                          Booking.com
                          <span style={styles.roomCount}>
                            {' '}{bookingData.latest_scrape ? `Scraped ${formatScrapeAge(bookingData.latest_scrape)}` : 'No scrape data'}
                            {' · '}
                            <Link to="/market" style={{ color: 'var(--navy)', textDecoration: 'none', fontSize: '13px' }}>
                              View details
                            </Link>
                          </span>
                        </td>
                        {data.dates.map(dateStr => (
                          <td key={dateStr} style={styles.categoryHeaderFill} />
                        ))}
                      </tr>
                      <tr>
                        <td style={mergeStyles(styles.td, styles.stickyCol, styles.tariffNameCell)}>
                          Best Available
                        </td>
                        {data.dates.map(dateStr => {
                          const entry = bookingData.dates[dateStr]
                          const isAvailable = entry?.status === 'available'
                          const isSoldOut = entry?.status === 'sold_out'
                          const getCellStyle = () => {
                            if (!entry) return styles.cellNoData
                            if (isAvailable && entry.rate) return styles.cellAvailable
                            if (isSoldOut) return styles.bookingCellSoldOut
                            return styles.cellNoData
                          }
                          return (
                            <td
                              key={dateStr}
                              style={mergeStyles(
                                styles.td,
                                styles.tariffCell,
                                isWeekend(dateStr) ? styles.weekendCell : {},
                                getCellStyle()
                              )}
                              title={
                                !entry ? 'No data'
                                  : isAvailable ? `Booking.com: ${formatCurrency(entry.rate)}`
                                  : isSoldOut ? 'Sold out on Booking.com'
                                  : 'No data'
                              }
                            >
                              {!entry ? '-'
                                : isAvailable && entry.rate ? formatCurrency(entry.rate)
                                : isSoldOut ? 'Sold'
                                : '-'}
                            </td>
                          )
                        })}
                      </tr>
                    </React.Fragment>
                  )}
                </tbody>
              </table>
            </div>
          </div>
        )}
      </div>

      {/* Issues Panel */}
      {summary && summary.unbookableDateCategories > 0 && (
        <div style={styles.issuesPanel}>
          <h3 style={styles.issuesTitle}>
            Unbookable Dates ({summary.totalIssues})
          </h3>
          <p style={styles.issuesSubtitle}>
            Dates with rooms available but no rates bookable
          </p>
          <div style={styles.issuesList}>
            {summary.issues.map((issue, idx) => (
              <div key={idx} style={styles.issueItem}>
                <span style={styles.issueCategory}>{issue.category}</span>
                <span style={styles.issueDate}>{issue.date}</span>
                <span style={styles.issueMessage}>{issue.roomsLeft} room{issue.roomsLeft !== 1 ? 's' : ''} available, no rates</span>
              </div>
            ))}
            {summary.hasMoreIssues && (
              <div style={styles.moreIssues}>
                +{summary.totalIssues - 10} more issues
              </div>
            )}
          </div>
        </div>
      )}

      {/* Legend */}
      <div style={styles.legend}>
        <span style={styles.legendTitle}>Legend:</span>
        <span style={mergeStyles(styles.legendItem, styles.cellAvailable)}>Available</span>
        <span style={mergeStyles(styles.legendItem, styles.cellUnavailable)}>Unavailable</span>
        <span style={mergeStyles(styles.legendItem, styles.cellNoRooms)}>No Rooms</span>
        <span style={mergeStyles(styles.legendItem, styles.cellNoData)}>No Data</span>
        <span style={{ marginLeft: 'auto', fontSize: 11, color: 'var(--text-mid)' }}>Click any cell for rate &amp; occupancy history</span>
      </div>

      {history && <OccHistoryModal target={history} onClose={() => setHistory(null)} />}
    </div>
  )
}

// Styles
const styles: Record<string, React.CSSProperties> = {
  container: {
    padding: '24px',
    maxWidth: '100%',
    margin: '0 auto',
  },
  header: {
    marginBottom: '24px',
  },
  headerTop: {
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'flex-start',
    marginBottom: '16px',
    flexWrap: 'wrap',
    gap: '16px',
  },
  title: {
    fontSize: '24px',
    fontWeight: 700,
    color: 'var(--text-dark)',
    margin: 0,
  },
  subtitle: {
    fontSize: '13px',
    color: 'var(--text-mid)',
    margin: '4px 0 0',
  },
  headerActions: {
    display: 'flex',
    alignItems: 'center',
    gap: '16px',
  },
  monthSelector: {
    display: 'flex',
    alignItems: 'center',
    gap: '8px',
  },
  monthDropdown: {
    fontSize: '14px',
    fontWeight: 500,
    color: 'var(--text-dark)',
    padding: '4px 8px',
    borderRadius: '6px',
    border: '1px solid var(--card-border)',
    background: 'var(--card-bg)',
    cursor: 'pointer',
    minWidth: '160px',
  },
  summaryBar: {
    display: 'flex',
    gap: '24px',
    padding: '16px',
    background: 'var(--card-bg)',
    borderRadius: '10px',
    boxShadow: 'var(--shadow-sm)',
    flexWrap: 'wrap',
  },
  summaryItem: {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    gap: '4px',
  },
  summaryValue: {
    fontSize: '20px',
    fontWeight: 700,
    color: 'var(--text-dark)',
  },
  summaryLabel: {
    fontSize: '11px',
    color: 'var(--text-mid)',
    textTransform: 'uppercase',
  },
  content: {
    display: 'flex',
    flexDirection: 'column',
    gap: '24px',
  },
  unifiedCard: {
    background: 'var(--card-bg)',
    borderRadius: '10px',
    padding: '16px',
    boxShadow: 'var(--shadow-md)',
  },
  categoryHeaderRow: {
    fontWeight: 600,
    fontSize: '14px',
    color: 'var(--text-dark)',
    background: 'var(--body-bg)',
    padding: '8px 16px',
    borderTop: '2px solid var(--card-border)',
    textAlign: 'left' as const,
    whiteSpace: 'nowrap' as const,
  },
  categoryHeaderFill: {
    background: 'var(--body-bg)',
    borderTop: '2px solid var(--card-border)',
    padding: 0,
  },
  stickyHeader: {
    position: 'sticky' as const,
    top: 0,
    zIndex: 20,
    background: 'var(--card-bg)',
  },
  roomCount: {
    fontSize: '13px',
    fontWeight: 400,
    color: 'var(--text-mid)',
  },
  tableContainer: {
    overflowX: 'auto',
    maxWidth: '100%',
  },
  table: {
    width: '100%',
    borderCollapse: 'collapse',
    fontSize: '13px',
    minWidth: '800px',
    tableLayout: 'fixed' as const,
  },
  th: {
    padding: '8px',
    borderBottom: '2px solid var(--card-border)',
    textAlign: 'center',
    fontWeight: 600,
    color: 'var(--text-dark)',
    whiteSpace: 'nowrap',
    background: 'var(--card-bg)',
  },
  td: {
    padding: '8px',
    borderBottom: '1px solid var(--card-border)',
    textAlign: 'center',
    whiteSpace: 'nowrap',
  },
  stickyCol: {
    position: 'sticky',
    left: 0,
    background: 'var(--card-bg)',
    zIndex: 10,
    textAlign: 'left',
    width: '160px',
    borderRight: '1px solid var(--card-border)',
    overflow: 'hidden',
    textOverflow: 'ellipsis',
  },
  dateHeader: {
    width: '56px',
    padding: '4px',
  },
  dateHeaderContent: {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    gap: '2px',
  },
  dayOfWeek: {
    fontSize: '11px',
    color: 'var(--text-mid)',
  },
  dayNum: {
    fontSize: '13px',
    fontWeight: 600,
  },
  lastUpdated: {
    fontSize: '9px',
    color: 'var(--text-mid)',
    opacity: 0.7,
    lineHeight: 1,
  },
  weekendHeader: {
    background: 'var(--body-bg)',
  },
  weekendCell: {
    borderLeft: '2px solid var(--card-border)',
  },
  tariffNameCell: {
    fontWeight: 500,
    overflow: 'hidden',
    textOverflow: 'ellipsis',
  },
  tariffCell: {
    cursor: 'pointer',
    position: 'relative',
    transition: 'background 0.1s',
    fontSize: '11px',
  },
  cellContent: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: '2px',
  },
  minStayBadge: {
    display: 'inline-flex',
    alignItems: 'center',
    justifyContent: 'center',
    width: '14px',
    height: '14px',
    borderRadius: '50%',
    background: '#d97706',
    color: '#fff',
    fontSize: '9px',
    fontWeight: 700,
    marginLeft: '2px',
    flexShrink: 0,
  },
  cellAvailable: {
    background: '#dcfce7',
    color: 'var(--success)',
  },
  cellUnavailable: {
    background: '#fee2e2',
    color: 'var(--danger)',
    textDecoration: 'line-through',
  },
  cellNoRooms: {
    background: '#e0e0e0',
    color: 'var(--text-mid)',
  },
  cellNoData: {
    background: 'var(--body-bg)',
    color: 'var(--text-mid)',
  },
  bookingCellSoldOut: {
    background: '#fee2e2',
    color: 'var(--danger)',
    fontWeight: 500,
  },
  occupancyLabel: {
    fontWeight: 600,
    color: 'var(--navy)',
    background: '#f0f4ff',
  },
  occupancyCell: {
    fontSize: '11px',
    color: 'var(--text-mid)',
    background: 'var(--body-bg)',
  },
  occupancyText: {
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    gap: '2px',
  },
  maintenanceBadge: {
    color: '#d97706',
    marginLeft: '2px',
  },
  occupancyAvailable: {
    background: '#dcfce7',
    color: 'var(--success)',
    fontWeight: 500,
  },
  occupancyHigh: {
    background: '#fef3c7',
    color: '#d97706',
    fontWeight: 500,
  },
  occupancyFull: {
    background: '#fee2e2',
    color: 'var(--danger)',
    fontWeight: 500,
  },
  loading: {
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'center',
    justifyContent: 'center',
    padding: '48px',
    gap: '16px',
    color: 'var(--text-mid)',
  },
  spinner: {
    width: '40px',
    height: '40px',
    border: '3px solid var(--card-border)',
    borderTop: '3px solid var(--navy)',
    borderRadius: '50%',
    animation: 'spin 1s linear infinite',
  },
  error: {
    display: 'flex',
    alignItems: 'center',
    gap: '8px',
    padding: '24px',
    background: '#fee2e2',
    color: 'var(--danger)',
    borderRadius: '10px',
  },
  errorIcon: {
    width: '24px',
    height: '24px',
    borderRadius: '50%',
    background: 'var(--danger)',
    color: '#fff',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    fontWeight: 700,
  },
  noData: {
    textAlign: 'center',
    padding: '32px',
    color: 'var(--text-mid)',
  },
  issuesPanel: {
    marginTop: '24px',
    background: '#fef3c7',
    borderRadius: '10px',
    padding: '24px',
  },
  issuesTitle: {
    fontSize: '14px',
    fontWeight: 600,
    color: '#d97706',
    marginBottom: '4px',
  },
  issuesSubtitle: {
    fontSize: '13px',
    color: 'var(--text-mid)',
    marginBottom: '16px',
  },
  issuesList: {
    display: 'flex',
    flexDirection: 'column',
    gap: '8px',
  },
  issueItem: {
    display: 'flex',
    gap: '8px',
    fontSize: '13px',
    flexWrap: 'wrap',
  },
  issueCategory: {
    fontWeight: 600,
    color: 'var(--text-dark)',
  },
  issueDate: {
    color: 'var(--text-mid)',
  },
  issueMessage: {
    color: 'var(--danger)',
    fontStyle: 'italic',
  },
  moreIssues: {
    color: 'var(--text-mid)',
    fontStyle: 'italic',
    marginTop: '8px',
  },
  legend: {
    display: 'flex',
    alignItems: 'center',
    gap: '16px',
    marginTop: '24px',
    padding: '16px',
    background: 'var(--card-bg)',
    borderRadius: '10px',
    fontSize: '13px',
  },
  legendTitle: {
    fontWeight: 600,
    color: 'var(--text-dark)',
  },
  legendItem: {
    padding: '4px 8px',
    borderRadius: '4px',
    fontSize: '11px',
  },
  scrapeBtn: {
    background: 'none',
    border: '1px solid var(--card-border)',
    borderRadius: '4px',
    cursor: 'pointer',
    fontSize: '10px',
    lineHeight: 1,
    padding: '2px 4px',
    color: 'var(--text-mid)',
    opacity: 0.6,
    transition: 'opacity 0.15s',
  },
  scrapeBtnActive: {
    opacity: 1,
    color: 'var(--navy)',
    borderColor: 'var(--navy)',
  },
}

// ─── Occupancy + Rate History Modal ──────────────────────────────────────────

interface RateHistorySnapshot {
  valid_from: string
  tariffs: { name: string; rate: number | null; available: boolean; min_stay?: number | null }[]
}

interface OccSnapshot {
  valid_from: string
  occupied: number
  available: number
  occupancy_pct: number | null
}

const PLOT_BASE = {
  paper_bgcolor: 'transparent',
  plot_bgcolor: 'transparent',
  font: { family: 'Inter, system-ui, sans-serif', size: 12, color: '#60748b' },
  margin: { t: 10, r: 24, b: 48, l: 52 },
  xaxis: { gridcolor: '#e5e9f0', zeroline: false },
  yaxis: { gridcolor: '#e5e9f0', zeroline: false },
}

const TRACE_COLORS = ['#2563eb', '#d97706', '#7c3aed', '#059669', '#0891b2', '#be185d']

function OccHistoryModal({ target, onClose }: { target: HistoryTarget; onClose: () => void }) {
  const { data: rateData, isLoading: rateLoading } = useQuery<{
    history: RateHistorySnapshot[]
    version_count: number
  }>({
    queryKey: ['bookability-rate-history', target.categoryId, target.date],
    queryFn: () => api.get(`/bookability/rate-history/${target.categoryId}/${target.date}`).then(r => r.data),
  })

  const { data: occData, isLoading: occLoading } = useQuery<{ snapshots: OccSnapshot[] }>({
    queryKey: ['bookability-occ-history', target.categoryId, target.date],
    queryFn: () => api.get(`/bookability/occupancy-history/${target.categoryId}/${target.date}`).then(r => r.data),
  })

  const rateTraces = useMemo(() => {
    const history = rateData?.history ?? []
    if (!history.length) return []
    const tariffNames = [...new Set(history.flatMap(h => h.tariffs.map(t => t.name)))]
    return tariffNames.map((name, i) => {
      const pts = history
        .map(h => ({ x: h.valid_from, t: h.tariffs.find(t => t.name === name) }))
        .filter(p => p.t?.rate != null)
      return {
        x: pts.map(p => p.x),
        y: pts.map(p => p.t!.rate),
        type: 'scatter' as const,
        mode: 'lines+markers' as const,
        name,
        line: { color: TRACE_COLORS[i % TRACE_COLORS.length], shape: 'hv' as const, width: 2 },
        marker: {
          size: 8,
          color: pts.map(p => p.t!.available ? '#16a34a' : '#dc2626'),
          symbol: pts.map(p => (p.t!.available ? 'circle' : 'x') as any),
          line: { color: TRACE_COLORS[i % TRACE_COLORS.length], width: 1 },
        },
      }
    })
  }, [rateData])

  const occTrace = useMemo(() => {
    const snaps = occData?.snapshots ?? []
    if (!snaps.length) return null
    return {
      x: snaps.map(s => s.valid_from),
      y: snaps.map(s => s.occupancy_pct),
      type: 'scatter' as const,
      mode: 'lines+markers' as const,
      name: 'Occupancy %',
      fill: 'tozeroy' as const,
      fillcolor: 'rgba(201,168,76,0.12)',
      line: { color: 'var(--gold, #c9a84c)', shape: 'hv' as const, width: 2 },
      marker: { size: 5, color: '#c9a84c' },
    }
  }, [occData])

  const isLoading = rateLoading || occLoading

  return (
    <div
      style={{ position: 'fixed', inset: 0, background: 'rgba(26,26,46,0.55)', zIndex: 200, display: 'flex', alignItems: 'center', justifyContent: 'center' }}
      onClick={onClose}
    >
      <div
        className="card"
        style={{ width: 'min(780px, 92vw)', maxHeight: '88vh', overflow: 'auto' }}
        onClick={e => e.stopPropagation()}
      >
        <div className="card-header" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <span style={{ fontWeight: 600 }}>{target.categoryName} — {target.date}</span>
          <button style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--text-mid)' }} onClick={onClose}>
            <X size={16} strokeWidth={1.75} />
          </button>
        </div>

        <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 24 }}>
          {isLoading && <div className="loading-state"><div className="spinner" />Loading history…</div>}

          {!isLoading && (
            <>
              {/* Rate history */}
              <div>
                <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text-mid)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>
                  Rate History
                  {rateData?.version_count ? <span style={{ fontWeight: 400, marginLeft: 8 }}>({rateData.version_count} change{rateData.version_count !== 1 ? 's' : ''})</span> : null}
                </div>
                {!rateTraces.length ? (
                  <div style={{ padding: '20px 0', color: 'var(--text-mid)', fontSize: 13, textAlign: 'center' }}>No rate history recorded yet.</div>
                ) : (
                  <>
                    <Plot
                      data={rateTraces}
                      layout={{
                        ...PLOT_BASE,
                        height: 240,
                        showlegend: true,
                        legend: { orientation: 'h' as const, y: -0.35, font: { size: 11 } },
                        yaxis: { ...PLOT_BASE.yaxis, tickprefix: '£', title: { text: '£ / night' } },
                      }}
                      config={{ displayModeBar: false, responsive: true }}
                      style={{ width: '100%' }}
                    />
                    <div style={{ fontSize: 11, color: 'var(--text-mid)', marginTop: 2 }}>
                      Green circle = available &nbsp;·&nbsp; Red ✕ = unavailable at that snapshot
                    </div>
                  </>
                )}
              </div>

              {/* Occupancy history */}
              <div>
                <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text-mid)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 8 }}>
                  Occupancy Pick-up
                  {occData?.snapshots.length ? <span style={{ fontWeight: 400, marginLeft: 8 }}>({occData.snapshots.length} snapshot{occData.snapshots.length !== 1 ? 's' : ''})</span> : null}
                </div>
                {!occTrace ? (
                  <div style={{ padding: '20px 0', color: 'var(--text-mid)', fontSize: 13, textAlign: 'center' }}>
                    No occupancy snapshots yet — pick-up history starts accumulating from first sync after this deployment.
                  </div>
                ) : (
                  <Plot
                    data={[occTrace]}
                    layout={{
                      ...PLOT_BASE,
                      height: 180,
                      showlegend: false,
                      yaxis: { ...PLOT_BASE.yaxis, range: [0, 100], ticksuffix: '%', title: { text: 'Occ %' } },
                    }}
                    config={{ displayModeBar: false, responsive: true }}
                    style={{ width: '100%' }}
                  />
                )}
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  )
}

export default Bookability
