'use client'
import { BASE } from '@/lib/basepath'

import { useState, useEffect, useCallback, useRef, useMemo } from 'react'
import { useRouter } from 'next/navigation'
import type { CatalogItem, ModifierList } from '@/data/mock-catalog'
import type { ItemOverride } from '@/lib/overrides'
import { DEFAULT_HOURS, minsToTime, timeToMins } from '@/lib/hours-config'
import type { HoursConfig, DayHours } from '@/lib/hours-config'
import AdminColorFilter from '@/components/AdminColorFilter'

// ─── Types ────────────────────────────────────────────────────────────────────

interface AdminItem extends CatalogItem {
  hidden: boolean
  sortOrder: number
  _rawCategory: string
  _rawCategoryLabel: string
  _rawShowColors: boolean
  _rawVariations: CatalogItem['variations']
  _rawModifiers: ModifierList[]
  _rawDescription: string
  _override: ItemOverride
}

interface SquareCategory { id: string; name: string }

// ─── Helpers ──────────────────────────────────────────────────────────────────

function cents(n: number | null) {
  if (n == null) return 'Custom quote'
  return `$${(n / 100).toFixed(2)}`
}

// ─── Category Display Editor ──────────────────────────────────────────────────

function CategoryDisplayEditor({ items }: { items: AdminItem[] }) {
  const [rows,   setRows]   = useState<{ key: string; label: string; hidden: boolean }[]>([])
  const [saving, setSaving] = useState(false)
  const [msg,    setMsg]    = useState('')

  // Derive unique display categories from items — same logic as the shop front-end
  const catalogCats = useMemo(() => {
    const seen = new Map<string, string>()
    items.forEach((item) => {
      const cats   = item.categories   ?? [item.category]
      const labels = item.categoryLabels ?? [item.categoryLabel]
      cats.forEach((slug, i) => {
        if (!seen.has(slug)) seen.set(slug, labels[i] ?? slug)
      })
    })
    return Array.from(seen.entries()).map(([key, label]) => ({ key, label }))
  }, [items])

  useEffect(() => {
    if (!catalogCats.length) return
    fetch(BASE + '/api/admin/categories-display')
      .then((r) => r.json())
      .then(({ order, hidden }: { order: string[]; hidden: string[] }) => {
        const inOrder = order
          .map((k) => catalogCats.find((c) => c.key === k))
          .filter((c): c is typeof catalogCats[number] => !!c)
          .map((c) => ({ ...c, hidden: hidden.includes(c.key) }))
        const rest = catalogCats
          .filter((c) => !order.includes(c.key))
          .map((c) => ({ ...c, hidden: hidden.includes(c.key) }))
        setRows([...inOrder, ...rest])
      })
      .catch(() => setRows(catalogCats.map((c) => ({ ...c, hidden: false }))))
  }, [catalogCats])

  function move(index: number, dir: -1 | 1) {
    const next = [...rows]
    const swap = index + dir
    if (swap < 0 || swap >= next.length) return
    ;[next[index], next[swap]] = [next[swap], next[index]]
    setRows(next)
  }

  function toggleHidden(key: string) {
    setRows((prev) => prev.map((r) => r.key === key ? { ...r, hidden: !r.hidden } : r))
  }

  async function handleSave() {
    setSaving(true)
    setMsg('')
    const res = await fetch(BASE + '/api/admin/categories-display', {
      method:  'PUT',
      headers: { 'Content-Type': 'application/json' },
      body:    JSON.stringify({
        order:  rows.map((r) => r.key),
        hidden: rows.filter((r) => r.hidden).map((r) => r.key),
      }),
    })
    setSaving(false)
    setMsg(res.ok ? 'Saved' : 'Save failed')
    setTimeout(() => setMsg(''), 3000)
  }

  if (!rows.length) return null

  return (
    <div>
      <p style={{ fontWeight: 600, fontSize: '0.9rem', marginBottom: '0.5rem' }}>Tab order &amp; visibility</p>
      <p className="is-size-7 has-text-grey" style={{ marginBottom: '0.75rem' }}>
        Controls which category tabs appear in the shop and in what order. Hidden categories still appear on individual items.
      </p>
      <table className="table is-narrow" style={{ fontSize: '0.85rem' }}>
        <tbody>
          {rows.map((row, i) => (
            <tr key={row.key} style={{ opacity: row.hidden ? 0.4 : 1 }}>
              <td style={{ verticalAlign: 'middle', paddingRight: 4 }}>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
                  <button
                    className="button is-white is-small"
                    style={{ padding: '0 6px', height: 18, minWidth: 0, lineHeight: 1 }}
                    disabled={i === 0}
                    onClick={() => move(i, -1)}
                    type="button"
                    title="Move up"
                  >▲</button>
                  <button
                    className="button is-white is-small"
                    style={{ padding: '0 6px', height: 18, minWidth: 0, lineHeight: 1 }}
                    disabled={i === rows.length - 1}
                    onClick={() => move(i, 1)}
                    type="button"
                    title="Move down"
                  >▼</button>
                </div>
              </td>
              <td style={{ verticalAlign: 'middle' }}>
                <span className="tag is-medium is-light">{row.label}</span>
              </td>
              <td style={{ verticalAlign: 'middle' }}>
                <label className="checkbox is-size-7">
                  <input
                    type="checkbox"
                    checked={!row.hidden}
                    onChange={() => toggleHidden(row.key)}
                    style={{ marginRight: 4 }}
                  />
                  Show in tabs
                </label>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <button
          className={`button is-light is-small${saving ? ' is-loading' : ''}`}
          onClick={handleSave}
          type="button"
        >
          Save tab order
        </button>
        {msg && (
          <span className={`is-size-7 ${msg === 'Saved' ? 'has-text-success' : 'has-text-danger'}`}>
            {msg}
          </span>
        )}
      </div>
    </div>
  )
}

// ─── Hours Editor ─────────────────────────────────────────────────────────────

const DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']

function HoursEditor() {
  const [config,  setConfig]  = useState<HoursConfig | null>(null)
  const [saving,  setSaving]  = useState(false)
  const [msg,     setMsg]     = useState('')

  useEffect(() => {
    fetch(BASE + '/api/admin/hours')
      .then((r) => r.json())
      .then(setConfig)
      .catch(() => setConfig(DEFAULT_HOURS))
  }, [])

  function setDay(type: 'delivery' | 'pickup', dow: number, value: DayHours | null) {
    setConfig((prev) => {
      if (!prev) return prev
      return { ...prev, [type]: { ...prev[type], [String(dow)]: value } }
    })
  }

  async function handleSave() {
    if (!config) return
    setSaving(true)
    setMsg('')
    const res = await fetch(BASE + '/api/admin/hours', {
      method:  'PUT',
      headers: { 'Content-Type': 'application/json' },
      body:    JSON.stringify(config),
    })
    setSaving(false)
    setMsg(res.ok ? 'Saved' : 'Save failed')
    setTimeout(() => setMsg(''), 3000)
  }

  if (!config) return <p className="has-text-grey">Loading…</p>

  return (
    <div>
      {(['delivery', 'pickup'] as const).map((type) => (
        <div key={type} style={{ marginBottom: '2rem' }}>
          <h3 className="is-size-6" style={{ fontWeight: 700, marginBottom: '0.75rem', textTransform: 'capitalize' }}>
            {type}
          </h3>
          <table className="table is-narrow is-fullwidth" style={{ fontSize: '0.85rem' }}>
            <thead>
              <tr>
                <th style={{ width: 110 }}>Day</th>
                <th style={{ width: 80 }}>Open</th>
                <th style={{ width: 120 }}>Opens at</th>
                <th style={{ width: 120 }}>Closes at</th>
              </tr>
            </thead>
            <tbody>
              {DAY_NAMES.map((dayName, dow) => {
                const hours = config[type][String(dow)] ?? null
                const isOpen = hours !== null
                return (
                  <tr key={dow}>
                    <td style={{ verticalAlign: 'middle' }}>{dayName}</td>
                    <td style={{ verticalAlign: 'middle' }}>
                      <label className="checkbox">
                        <input
                          type="checkbox"
                          checked={isOpen}
                          onChange={(e) => {
                            if (e.target.checked) {
                              const def = DEFAULT_HOURS[type][String(dow)]
                              setDay(type, dow, def ?? { open: 600, close: 960 })
                            } else {
                              setDay(type, dow, null)
                            }
                          }}
                          style={{ marginRight: 4 }}
                        />
                        Open
                      </label>
                    </td>
                    <td>
                      <input
                        type="time"
                        className="input is-small"
                        disabled={!isOpen}
                        value={isOpen ? minsToTime(hours!.open) : ''}
                        step={1800}
                        onChange={(e) => {
                          if (!isOpen) return
                          setDay(type, dow, { ...hours!, open: timeToMins(e.target.value) })
                        }}
                        style={{ width: 110 }}
                      />
                    </td>
                    <td>
                      <input
                        type="time"
                        className="input is-small"
                        disabled={!isOpen}
                        value={isOpen ? minsToTime(hours!.close) : ''}
                        step={1800}
                        onChange={(e) => {
                          if (!isOpen) return
                          setDay(type, dow, { ...hours!, close: timeToMins(e.target.value) })
                        }}
                        style={{ width: 110 }}
                      />
                    </td>
                  </tr>
                )
              })}
            </tbody>
          </table>
        </div>
      ))}

      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <button
          className={`button is-dark is-small${saving ? ' is-loading' : ''}`}
          onClick={handleSave}
          type="button"
        >
          Save hours
        </button>
        {msg && (
          <span className={`is-size-7 ${msg === 'Saved' ? 'has-text-success' : 'has-text-danger'}`}>
            {msg}
          </span>
        )}
      </div>
      <p className="help" style={{ marginTop: '0.5rem' }}>
        Changes take effect immediately. Delivery slots already visible to customers are not affected until they reload.
      </p>
    </div>
  )
}

// ─── Occasions Editor ─────────────────────────────────────────────────────────

interface OccasionRow {
  key:                    string
  label:                  string
  emoji:                  string
  defaultSlug:            string
  isCustom:               boolean
  enabled:                boolean
  squareCategorySlug:     string
  windowStart:            string | null
  windowEnd:              string | null
  windowStartOverridden:  boolean
  windowEndOverridden:    boolean
  defaultWindowStart:     string | null
  defaultWindowEnd:       string | null
  blurb?:                 string
}

const EMPTY_NEW = { emoji: '', label: '', blurb: '', squareCategorySlug: '', windowStart: '', windowEnd: '' }

function OccasionsEditor() {
  const [rows,      setRows]      = useState<OccasionRow[]>([])
  const [saving,    setSaving]    = useState(false)
  const [msg,       setMsg]       = useState('')
  const [showForm,  setShowForm]  = useState(false)
  const [newOcc,    setNewOcc]    = useState(EMPTY_NEW)

  useEffect(() => {
    fetch(BASE + '/api/admin/occasions')
      .then((r) => r.json())
      .then(({ occasions }: { occasions: OccasionRow[] }) => setRows(occasions))
      .catch(() => {})
  }, [])

  function update(key: string, patch: Partial<OccasionRow>) {
    setRows((prev) => prev.map((r) => r.key === key ? { ...r, ...patch } : r))
  }

  function deleteRow(key: string) {
    setRows((prev) => prev.filter((r) => r.key !== key))
  }

  function addCustom() {
    if (!newOcc.label || !newOcc.windowStart || !newOcc.windowEnd) return
    const key = `custom_${newOcc.label.toLowerCase().replace(/[^a-z0-9]+/g, '-')}_${Date.now()}`
    const row: OccasionRow = {
      key,
      label:                 newOcc.label,
      emoji:                 newOcc.emoji || '🎉',
      defaultSlug:           '',
      isCustom:              true,
      enabled:               true,
      squareCategorySlug:    newOcc.squareCategorySlug,
      windowStart:           newOcc.windowStart,
      windowEnd:             newOcc.windowEnd,
      windowStartOverridden: true,
      windowEndOverridden:   true,
      defaultWindowStart:    null,
      defaultWindowEnd:      null,
      blurb:                 newOcc.blurb,
    }
    setRows((prev) => [...prev, row])
    setNewOcc(EMPTY_NEW)
    setShowForm(false)
  }

  async function handleSave() {
    setSaving(true)
    setMsg('')
    const config: Record<string, object> = {}
    for (const r of rows) {
      if (r.isCustom) {
        config[r.key] = {
          custom:             true,
          enabled:            r.enabled,
          label:              r.label,
          emoji:              r.emoji,
          blurb:              r.blurb ?? '',
          squareCategorySlug: r.squareCategorySlug || undefined,
          windowStart:        (r.windowStart ?? '').slice(5),  // YYYY-MM-DD → MM-DD
          windowEnd:          (r.windowEnd   ?? '').slice(5),
        }
      } else {
        const ov: Record<string, unknown> = {}
        if (!r.enabled) ov.enabled = false
        if (r.squareCategorySlug !== r.defaultSlug) ov.squareCategorySlug = r.squareCategorySlug
        if (r.windowStartOverridden && r.windowStart) ov.windowStart = r.windowStart.slice(5)
        if (r.windowEndOverridden   && r.windowEnd)   ov.windowEnd   = r.windowEnd.slice(5)
        if (Object.keys(ov).length) config[r.key] = ov
      }
    }
    const res = await fetch(BASE + '/api/admin/occasions', {
      method:  'PUT',
      headers: { 'Content-Type': 'application/json' },
      body:    JSON.stringify(config),
    })
    setSaving(false)
    setMsg(res.ok ? 'Saved' : 'Save failed')
    setTimeout(() => setMsg(''), 3000)
  }

  if (!rows.length) return <p className="has-text-grey">Loading…</p>

  return (
    <div>
      <p className="is-size-7 has-text-grey" style={{ marginBottom: '1rem' }}>
        Control which holiday tabs appear in the shop, which Square category they filter, and the date window during which the tab is shown.
      </p>
      <table className="table is-narrow is-fullwidth" style={{ fontSize: '0.85rem' }}>
        <thead>
          <tr>
            <th style={{ width: 160 }}>Holiday</th>
            <th style={{ width: 60 }}>Show</th>
            <th style={{ minWidth: 180 }}>Square category slug</th>
            <th style={{ width: 145 }}>Window opens</th>
            <th style={{ width: 145 }}>Window closes</th>
            <th style={{ width: 36 }} />
          </tr>
        </thead>
        <tbody>
          {rows.map((row) => (
            <tr key={row.key} style={{ opacity: row.enabled ? 1 : 0.45 }}>
              <td style={{ verticalAlign: 'middle' }}>
                {row.emoji} {row.label}
              </td>
              <td style={{ verticalAlign: 'middle' }}>
                <label className="checkbox">
                  <input
                    type="checkbox"
                    checked={row.enabled}
                    onChange={(e) => update(row.key, { enabled: e.target.checked })}
                    style={{ marginRight: 4 }}
                  />
                  On
                </label>
              </td>
              <td style={{ verticalAlign: 'middle' }}>
                <input
                  className="input is-small"
                  value={row.squareCategorySlug}
                  disabled={!row.enabled}
                  placeholder={row.defaultSlug || 'none'}
                  onChange={(e) => update(row.key, { squareCategorySlug: e.target.value })}
                  style={{ width: '100%', maxWidth: 210 }}
                />
                {row.defaultSlug && row.squareCategorySlug !== row.defaultSlug && (
                  <div className="is-size-7 has-text-grey">default: {row.defaultSlug}</div>
                )}
              </td>
              <td style={{ verticalAlign: 'middle' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
                  <input
                    type="date"
                    className={`input is-small${row.windowStartOverridden ? '' : ' has-text-grey'}`}
                    disabled={!row.enabled}
                    value={row.windowStart ?? ''}
                    onChange={(e) => update(row.key, { windowStart: e.target.value, windowStartOverridden: true })}
                    style={{ width: 130 }}
                  />
                  {!row.isCustom && row.windowStartOverridden && row.windowStart !== row.defaultWindowStart && (
                    <button
                      className="delete is-small"
                      title="Reset to computed"
                      onClick={() => update(row.key, { windowStart: row.defaultWindowStart, windowStartOverridden: false })}
                    />
                  )}
                </div>
                {!row.isCustom && !row.windowStartOverridden && (
                  <div className="is-size-7 has-text-grey">computed</div>
                )}
              </td>
              <td style={{ verticalAlign: 'middle' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
                  <input
                    type="date"
                    className={`input is-small${row.windowEndOverridden ? '' : ' has-text-grey'}`}
                    disabled={!row.enabled}
                    value={row.windowEnd ?? ''}
                    onChange={(e) => update(row.key, { windowEnd: e.target.value, windowEndOverridden: true })}
                    style={{ width: 130 }}
                  />
                  {!row.isCustom && row.windowEndOverridden && row.windowEnd !== row.defaultWindowEnd && (
                    <button
                      className="delete is-small"
                      title="Reset to computed"
                      onClick={() => update(row.key, { windowEnd: row.defaultWindowEnd, windowEndOverridden: false })}
                    />
                  )}
                </div>
                {!row.isCustom && !row.windowEndOverridden && (
                  <div className="is-size-7 has-text-grey">computed</div>
                )}
              </td>
              <td style={{ verticalAlign: 'middle', textAlign: 'center' }}>
                {row.isCustom && (
                  <button
                    className="delete"
                    title="Remove holiday"
                    onClick={() => deleteRow(row.key)}
                  />
                )}
              </td>
            </tr>
          ))}
        </tbody>
      </table>

      {/* Add new custom holiday */}
      {showForm ? (
        <div style={{ border: '1px solid #ddd', borderRadius: 6, padding: '1rem', marginBottom: '1rem', background: '#fafafa' }}>
          <p style={{ fontWeight: 600, marginBottom: '0.75rem', fontSize: '0.9rem' }}>New holiday</p>
          <div className="columns is-mobile is-multiline" style={{ gap: 0 }}>
            <div className="column is-narrow">
              <label className="label is-small">Emoji</label>
              <input className="input is-small" value={newOcc.emoji} onChange={(e) => setNewOcc((p) => ({ ...p, emoji: e.target.value }))} style={{ width: 60 }} placeholder="🎉" />
            </div>
            <div className="column">
              <label className="label is-small">Label</label>
              <input className="input is-small" value={newOcc.label} onChange={(e) => setNewOcc((p) => ({ ...p, label: e.target.value }))} placeholder="Summer Sale" />
            </div>
            <div className="column is-full" style={{ paddingTop: 0 }}>
              <label className="label is-small">Short description (shown in banner)</label>
              <input className="input is-small" value={newOcc.blurb} onChange={(e) => setNewOcc((p) => ({ ...p, blurb: e.target.value }))} placeholder="Browse our summer collection." />
            </div>
            <div className="column">
              <label className="label is-small">Square category slug</label>
              <input className="input is-small" value={newOcc.squareCategorySlug} onChange={(e) => setNewOcc((p) => ({ ...p, squareCategorySlug: e.target.value }))} placeholder="summer-sale" />
            </div>
            <div className="column is-narrow">
              <label className="label is-small">Window opens</label>
              <input type="date" className="input is-small" value={newOcc.windowStart} onChange={(e) => setNewOcc((p) => ({ ...p, windowStart: e.target.value }))} style={{ width: 140 }} />
            </div>
            <div className="column is-narrow">
              <label className="label is-small">Window closes</label>
              <input type="date" className="input is-small" value={newOcc.windowEnd} onChange={(e) => setNewOcc((p) => ({ ...p, windowEnd: e.target.value }))} style={{ width: 140 }} />
            </div>
          </div>
          <div style={{ display: 'flex', gap: 8, marginTop: '0.5rem' }}>
            <button
              className="button is-dark is-small"
              type="button"
              disabled={!newOcc.label || !newOcc.windowStart || !newOcc.windowEnd}
              onClick={addCustom}
            >
              Add
            </button>
            <button className="button is-small" type="button" onClick={() => { setShowForm(false); setNewOcc(EMPTY_NEW) }}>
              Cancel
            </button>
          </div>
        </div>
      ) : (
        <button
          className="button is-small"
          type="button"
          style={{ marginBottom: '1rem' }}
          onClick={() => setShowForm(true)}
        >
          + Add holiday
        </button>
      )}

      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <button
          className={`button is-dark is-small${saving ? ' is-loading' : ''}`}
          onClick={handleSave}
          type="button"
        >
          Save holidays
        </button>
        {msg && (
          <span className={`is-size-7 ${msg === 'Saved' ? 'has-text-success' : 'has-text-danger'}`}>
            {msg}
          </span>
        )}
      </div>
      <p className="help" style={{ marginTop: '0.5rem' }}>
        Dates showing "computed" are auto-calculated each year (e.g. Easter, nth weekday). Click the date to override; the × resets to computed. Changes take effect immediately.
      </p>
    </div>
  )
}

// ─── Delivery Rates Editor ────────────────────────────────────────────────────

interface TierRate { base: number; perMile: number; label: string }
interface DeliveryRatesConfig { dropoff: TierRate; classic: TierRate; organic: TierRate }

const TIER_LABELS: Record<string, string> = {
  dropoff: 'Drop-off',
  classic: 'Setup & strike',
  organic: 'Organic setup & strike',
}

function DeliveryRatesEditor() {
  const [rates,  setRates]  = useState<DeliveryRatesConfig | null>(null)
  const [saving, setSaving] = useState(false)
  const [msg,    setMsg]    = useState('')

  useEffect(() => {
    fetch(BASE + '/api/admin/delivery-rates')
      .then((r) => r.json())
      .then(setRates)
      .catch(() => {})
  }, [])

  function updateTier(tier: keyof DeliveryRatesConfig, field: keyof TierRate, value: string) {
    setRates((prev) => {
      if (!prev) return prev
      const updated = { ...prev[tier] }
      if (field === 'label') {
        updated.label = value
      } else {
        updated[field] = Math.round(parseFloat(value) * 100) || 0
      }
      return { ...prev, [tier]: updated }
    })
  }

  async function handleSave() {
    if (!rates) return
    setSaving(true)
    setMsg('')
    const res = await fetch(BASE + '/api/admin/delivery-rates', {
      method:  'PUT',
      headers: { 'Content-Type': 'application/json' },
      body:    JSON.stringify(rates),
    })
    setSaving(false)
    setMsg(res.ok ? 'Saved' : 'Save failed')
    setTimeout(() => setMsg(''), 3000)
  }

  if (!rates) return <p className="has-text-grey">Loading…</p>

  return (
    <div>
      <p className="is-size-7 has-text-grey" style={{ marginBottom: '1rem' }}>
        Set the base fee and per-mile rate for each delivery type. Changes apply to new quotes immediately.
      </p>
      <table className="table is-narrow is-fullwidth" style={{ fontSize: '0.85rem' }}>
        <thead>
          <tr>
            <th style={{ minWidth: 200 }}>Tier</th>
            <th style={{ width: 130 }}>Base fee ($)</th>
            <th style={{ width: 130 }}>Per mile ($)</th>
            <th style={{ minWidth: 240 }}>Label</th>
          </tr>
        </thead>
        <tbody>
          {(['dropoff', 'classic', 'organic'] as const).map((tier) => (
            <tr key={tier}>
              <td style={{ verticalAlign: 'middle', fontWeight: 500 }}>{TIER_LABELS[tier]}</td>
              <td style={{ verticalAlign: 'middle' }}>
                <input
                  type="number"
                  min={0}
                  step={0.01}
                  className="input is-small"
                  value={(rates[tier].base / 100).toFixed(2)}
                  onChange={(e) => updateTier(tier, 'base', e.target.value)}
                  style={{ width: 100 }}
                />
              </td>
              <td style={{ verticalAlign: 'middle' }}>
                <input
                  type="number"
                  min={0}
                  step={0.01}
                  className="input is-small"
                  value={(rates[tier].perMile / 100).toFixed(2)}
                  onChange={(e) => updateTier(tier, 'perMile', e.target.value)}
                  style={{ width: 100 }}
                />
              </td>
              <td style={{ verticalAlign: 'middle' }}>
                <input
                  type="text"
                  className="input is-small"
                  value={rates[tier].label}
                  onChange={(e) => updateTier(tier, 'label', e.target.value)}
                  style={{ width: '100%' }}
                />
              </td>
            </tr>
          ))}
        </tbody>
      </table>
      <p className="help" style={{ marginBottom: '0.75rem' }}>
        Formula: <strong>base + ceil(miles) × per-mile</strong>. Example: drop-off to a 5-mile address =
        {' '}base + 5 × per-mile.
      </p>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <button
          className={`button is-dark is-small${saving ? ' is-loading' : ''}`}
          onClick={handleSave}
          type="button"
        >
          Save rates
        </button>
        {msg && (
          <span className={`is-size-7 ${msg === 'Saved' ? 'has-text-success' : 'has-text-danger'}`}>
            {msg}
          </span>
        )}
      </div>
    </div>
  )
}

// ─── Item Editor ──────────────────────────────────────────────────────────────

function ItemEditor({
  item,
  categories,
  onSaved,
  onCreateCategory,
}: {
  item: AdminItem
  categories: SquareCategory[]
  onSaved: (id: string, ov: Partial<ItemOverride>) => void
  onCreateCategory: (name: string) => Promise<SquareCategory>
}) {
  const ov = item._override

  const [hidden,           setHidden]           = useState(ov.hidden   ?? false)
  const [featured,         setFeatured]         = useState(ov.featured ?? item.featured ?? false)
  // Multi-category selection: stores category names (labels). Initialise from new override or fall back to Square assignment.
  const [selectedCatNames, setSelectedCatNames] = useState<string[]>(
    ov.categoriesOverride ?? item.categoryLabels ?? [item.categoryLabel]
  )
  const [sortOrder,    setSortOrder]    = useState(String(ov.sortOrder ?? ''))
  const [showColors,   setShowColors]   = useState<boolean | null>(
    ov.showColors != null ? ov.showColors : null
  )
  const [hiddenVars,   setHiddenVars]   = useState<string[]>(ov.hiddenVariationIds ?? [])
  const [hiddenMods,   setHiddenMods]   = useState<string[]>(ov.hiddenModifierIds ?? [])
  const [descOverride, setDescOverride] = useState(ov.descriptionOverride ?? '')
  const [saving,       setSaving]       = useState(false)
  const [saved,        setSaved]        = useState(false)
  const [error,        setError]        = useState('')

  // Per-modifier min overrides
  const [modifierMins, setModifierMins] = useState<Record<string, number>>(
    ov.modifierMinSelected ?? {}
  )

  // Image upload
  const fileInputRef    = useRef<HTMLInputElement>(null)
  const [uploading,     setUploading]   = useState(false)
  const [uploadResults, setUploadResults] = useState<{ name: string; url?: string | null; error?: string }[]>([])

  // Color limits
  const [colorMin,              setColorMin]              = useState<string>(String(ov.colorMin ?? ''))
  const [colorMax,              setColorMax]              = useState<string>(ov.colorMax != null ? String(ov.colorMax) : '')
  const [chromeSurcharge,       setChromeSurcharge]       = useState<string>(
    ov.chromeSurchargePerColor ? String(ov.chromeSurchargePerColor / 100) : ''
  )
  const [disabledColors,        setDisabledColors]        = useState<string[]>(ov.disabledColors ?? [])
  const [showColorFilter,       setShowColorFilter]       = useState(false)
  const [quantityUnit,          setQuantityUnit]          = useState<string>(ov.quantityUnit ?? '')
  const [requiresDelivery,      setRequiresDelivery]      = useState(ov.requiresDelivery ?? false)
  const [deliveryBase,          setDeliveryBase]          = useState<string>(
    ov.deliveryBaseOverride != null ? String(ov.deliveryBaseOverride / 100) : ''
  )
  const [deliveryPerMile,       setDeliveryPerMile]       = useState<string>(
    ov.deliveryPerMileOverride != null ? String(ov.deliveryPerMileOverride / 100) : ''
  )

  // Create category
  const [newCatName,  setNewCatName]   = useState('')
  const [creatingCat, setCreatingCat]  = useState(false)
  const [showNewCat,  setShowNewCat]   = useState(false)

  function toggleVar(id: string) {
    setHiddenVars((prev) =>
      prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]
    )
  }

  function toggleMod(id: string) {
    setHiddenMods((prev) =>
      prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]
    )
  }

  async function handleSave() {
    setSaving(true)
    setError('')
    const patch: Partial<ItemOverride> = {
      hidden,
      featured,
      hiddenVariationIds: hiddenVars,
      hiddenModifierIds: hiddenMods,
    }
    // Always save categoriesOverride (replaces old single-field overrides)
    patch.categoriesOverride = selectedCatNames
    if (sortOrder !== '') patch.sortOrder = Number(sortOrder)
    if (showColors !== null) patch.showColors = showColors
    if (descOverride) patch.descriptionOverride = descOverride
    if (Object.keys(modifierMins).length) patch.modifierMinSelected = modifierMins
    if (colorMin !== '') patch.colorMin = Number(colorMin)
    if (colorMax !== '') patch.colorMax = Number(colorMax)
    if (chromeSurcharge !== '') patch.chromeSurchargePerColor = Math.round(Number(chromeSurcharge) * 100)
    patch.disabledColors = disabledColors.length ? disabledColors : undefined
    if (quantityUnit.trim()) patch.quantityUnit = quantityUnit.trim()
    else patch.quantityUnit = undefined
    patch.requiresDelivery = requiresDelivery || undefined
    patch.deliveryBaseOverride    = deliveryBase    !== '' ? Math.round(Number(deliveryBase)    * 100) : null
    patch.deliveryPerMileOverride = deliveryPerMile !== '' ? Math.round(Number(deliveryPerMile) * 100) : null

    const res = await fetch(`${BASE}/api/admin/items/${item.id}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(patch),
    })
    setSaving(false)
    if (res.ok) {
      setSaved(true)
      setTimeout(() => setSaved(false), 2000)
      onSaved(item.id, patch)
    } else {
      setError('Save failed')
    }
  }

  async function handleReset() {
    if (!confirm('Reset all overrides for this item to Square defaults?')) return
    const res = await fetch(`${BASE}/api/admin/items/${item.id}`, { method: 'DELETE' })
    if (res.ok) {
      setHidden(false)
      setFeatured(item.featured ?? false)
      setSelectedCatNames(item.categoryLabels ?? [item.categoryLabel])
      setSortOrder('')
      setShowColors(null)
      setHiddenMods([])
      setDescOverride('')
      setModifierMins({})
      setColorMin('')
      setColorMax('')
      setChromeSurcharge('')
      setRequiresDelivery(false)
      setDeliveryBase('')
      setDeliveryPerMile('')
      onSaved(item.id, {})
    }
  }

  async function handleImageUpload(e: React.ChangeEvent<HTMLInputElement>) {
    const files = Array.from(e.target.files ?? [])
    if (!files.length) return
    setUploading(true)
    setUploadResults([])
    const fd = new FormData()
    files.forEach((f) => fd.append('images', f))
    const res = await fetch(`${BASE}/api/admin/items/${item.id}/images`, { method: 'POST', body: fd })
    const data = await res.json()
    setUploadResults(data.results ?? [])
    setUploading(false)
    if (fileInputRef.current) fileInputRef.current.value = ''
  }

  async function handleCreateCategory() {
    if (!newCatName.trim()) return
    setCreatingCat(true)
    const cat = await onCreateCategory(newCatName.trim())
    // Auto-select the newly created category
    if (cat.id) setSelectedCatNames((prev) => [...prev, cat.name])
    setNewCatName('')
    setShowNewCat(false)
    setCreatingCat(false)
  }

  return (
    <div style={{ padding: '1rem', borderTop: '1px solid #eee', backgroundColor: '#fafafa' }}>
      <div className="columns is-multiline">

        {/* Left column */}
        <div className="column is-half">

          {/* Visibility toggles */}
          <div className="field" style={{ display: 'flex', gap: '1.5rem', flexWrap: 'wrap' }}>
            <label className="checkbox" style={{ fontWeight: 600 }}>
              <input
                type="checkbox"
                checked={hidden}
                onChange={(e) => setHidden(e.target.checked)}
                style={{ marginRight: 6 }}
              />
              Hidden from storefront
            </label>
            <label className="checkbox" style={{ fontWeight: 600, color: '#11b3be' }}>
              <input
                type="checkbox"
                checked={featured}
                onChange={(e) => setFeatured(e.target.checked)}
                style={{ marginRight: 6, accentColor: '#11b3be' }}
              />
              ⭐ Featured
            </label>
            <label className="checkbox" style={{ fontWeight: 600, color: '#c0392b' }}>
              <input
                type="checkbox"
                checked={requiresDelivery}
                onChange={(e) => setRequiresDelivery(e.target.checked)}
                style={{ marginRight: 6, accentColor: '#c0392b' }}
              />
              🚗 Requires delivery
            </label>
          </div>

          {requiresDelivery && (
            <div className="field" style={{ background: '#fff8f8', border: '1px solid #f5c6c6', borderRadius: 6, padding: '0.6rem 0.8rem', marginBottom: '0.75rem' }}>
              <p className="is-size-7 has-text-grey" style={{ marginBottom: '0.4rem' }}>
                Custom delivery rates for this item (leave blank to use global tier defaults)
              </p>
              <div style={{ display: 'flex', gap: '1rem', flexWrap: 'wrap' }}>
                <div>
                  <label className="label is-small" style={{ marginBottom: 2 }}>Base charge ($)</label>
                  <input
                    className="input is-small"
                    type="number"
                    min="0"
                    step="0.01"
                    placeholder="e.g. 75.00"
                    value={deliveryBase}
                    onChange={(e) => setDeliveryBase(e.target.value)}
                    style={{ width: 110 }}
                  />
                </div>
                <div>
                  <label className="label is-small" style={{ marginBottom: 2 }}>Per mile ($)</label>
                  <input
                    className="input is-small"
                    type="number"
                    min="0"
                    step="0.01"
                    placeholder="e.g. 4.00"
                    value={deliveryPerMile}
                    onChange={(e) => setDeliveryPerMile(e.target.value)}
                    style={{ width: 110 }}
                  />
                </div>
              </div>
            </div>
          )}

          {/* Category — multi-select checkboxes */}
          <div className="field">
            <label className="label is-small">Categories <span className="has-text-grey-light" style={{ fontWeight: 'normal' }}>(item appears in all checked tabs)</span></label>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 4, maxHeight: 160, overflowY: 'auto', border: '1px solid #e8e8e8', borderRadius: 6, padding: '6px 8px' }}>
              {categories.map((c) => (
                <label key={c.id} className="checkbox" style={{ fontSize: '0.85rem' }}>
                  <input
                    type="checkbox"
                    checked={selectedCatNames.includes(c.name)}
                    onChange={(e) => {
                      setSelectedCatNames((prev) =>
                        e.target.checked ? [...prev, c.name] : prev.filter((n) => n !== c.name)
                      )
                    }}
                    style={{ marginRight: 6 }}
                  />
                  {c.name}
                  {(item.categoryLabels ?? [item.categoryLabel]).includes(c.name) && (
                    <span className="has-text-grey-light" style={{ fontSize: '0.72rem', marginLeft: 6 }}>Square</span>
                  )}
                </label>
              ))}
              {categories.length === 0 && (
                <p className="is-size-7 has-text-grey">No categories found — refresh from Square.</p>
              )}
            </div>
            <button
              className="button is-ghost is-small"
              style={{ padding: '0 2px', fontSize: '0.75rem', marginTop: 4 }}
              onClick={() => setShowNewCat(!showNewCat)}
              type="button"
            >
              + Create new category in Square
            </button>
            {showNewCat && (
              <div className="field has-addons" style={{ marginTop: 6 }}>
                <div className="control is-expanded">
                  <input
                    className="input is-small"
                    placeholder="New category name"
                    value={newCatName}
                    onChange={(e) => setNewCatName(e.target.value)}
                    onKeyDown={(e) => e.key === 'Enter' && handleCreateCategory()}
                  />
                </div>
                <div className="control">
                  <button
                    className={`button is-small is-dark${creatingCat ? ' is-loading' : ''}`}
                    onClick={handleCreateCategory}
                    type="button"
                  >
                    Create
                  </button>
                </div>
              </div>
            )}
          </div>

          {/* Sort order */}
          <div className="field">
            <label className="label is-small">Sort order <span className="has-text-grey-light">(lower = first, 0 = unsorted)</span></label>
            <div className="control">
              <input
                className="input is-small"
                type="number"
                value={sortOrder}
                onChange={(e) => setSortOrder(e.target.value)}
                style={{ width: 100 }}
              />
            </div>
          </div>

          {/* Show colors override */}
          {(item._rawShowColors || showColors) && (
            <div className="field">
              <label className="label is-small">Latex color picker</label>
              <div className="control">
                <label className="radio" style={{ marginRight: 12 }}>
                  <input
                    type="radio"
                    name={`colors-${item.id}`}
                    checked={showColors === null}
                    onChange={() => setShowColors(null)}
                  />{' '}
                  Square default ({item._rawShowColors ? 'on' : 'off'})
                </label>
                <label className="radio" style={{ marginRight: 12 }}>
                  <input
                    type="radio"
                    name={`colors-${item.id}`}
                    checked={showColors === true}
                    onChange={() => setShowColors(true)}
                  />{' '}
                  Always on
                </label>
                <label className="radio">
                  <input
                    type="radio"
                    name={`colors-${item.id}`}
                    checked={showColors === false}
                    onChange={() => setShowColors(false)}
                  />{' '}
                  Always off
                </label>
              </div>
            </div>
          )}

          {/* Description override */}
          <div className="field">
            <label className="label is-small">Description override <span className="has-text-grey-light">(leave blank to use Square)</span></label>
            <div className="control">
              <textarea
                className="textarea is-small"
                rows={3}
                placeholder={item._rawDescription || 'Square description'}
                value={descOverride}
                onChange={(e) => setDescOverride(e.target.value)}
              />
            </div>
          </div>
        </div>

        {/* Right column */}
        <div className="column is-half">

          {/* Variations */}
          {item._rawVariations.length > 1 && (
            <div className="field">
              <label className="label is-small">Variations</label>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {item._rawVariations.map((v) => {
                  const visible = !hiddenVars.includes(v.id)
                  return (
                    <div key={v.id} style={{
                      border: '1px solid #e8e8e8',
                      borderRadius: 6,
                      padding: '8px 10px',
                      background: visible ? '#fff' : '#fafafa',
                      opacity: visible ? 1 : 0.5,
                    }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                        <label className="checkbox" style={{ fontWeight: 500, fontSize: '0.875rem' }}>
                          <input
                            type="checkbox"
                            checked={visible}
                            onChange={() => toggleVar(v.id)}
                            style={{ marginRight: 6 }}
                          />
                          {v.name}
                        </label>
                        <span className="has-text-grey-light" style={{ fontSize: '0.75rem' }}>
                          ${(v.priceCents / 100).toFixed(2)}
                        </span>
                      </div>
                    </div>
                  )
                })}
              </div>
            </div>
          )}

          {/* Modifiers */}
          {item._rawModifiers.length > 0 && (
            <div className="field">
              <label className="label is-small">Modifiers</label>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
                {item._rawModifiers.map((m) => {
                  const visible = !hiddenMods.includes(m.id)
                  const squareMin = m.minSelected ?? 0
                  const currentMin = modifierMins[m.id] ?? squareMin
                  const isRequired = currentMin > 0

                  return (
                    <div key={m.id} style={{
                      border: '1px solid #e8e8e8',
                      borderRadius: 6,
                      padding: '8px 10px',
                      background: visible ? '#fff' : '#fafafa',
                      opacity: visible ? 1 : 0.5,
                    }}>
                      {/* Show / hide toggle */}
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                        <label className="checkbox" style={{ fontWeight: 500, fontSize: '0.875rem' }}>
                          <input
                            type="checkbox"
                            checked={visible}
                            onChange={() => toggleMod(m.id)}
                            style={{ marginRight: 6 }}
                          />
                          {m.name}
                        </label>
                        <span className="has-text-grey-light" style={{ fontSize: '0.75rem' }}>
                          {m.options.length} options · {m.selectionType.toLowerCase()}
                        </span>

                        {/* Required toggle — only when modifier is visible */}
                        {visible && (
                          <label className="checkbox" style={{ fontSize: '0.8rem', marginLeft: 'auto' }}>
                            <input
                              type="checkbox"
                              checked={isRequired}
                              onChange={(e) => {
                                setModifierMins((prev) => {
                                  const next = { ...prev }
                                  if (e.target.checked) {
                                    next[m.id] = Math.max(1, squareMin)
                                  } else {
                                    next[m.id] = 0
                                  }
                                  return next
                                })
                              }}
                              style={{ marginRight: 4 }}
                            />
                            Required
                          </label>
                        )}

                        {/* Min count — when required */}
                        {visible && isRequired && (
                          <div style={{ display: 'flex', alignItems: 'center', gap: 4, fontSize: '0.8rem' }}>
                            <span className="has-text-grey">min:</span>
                            <input
                              type="number"
                              min={1}
                              max={m.options.length}
                              value={currentMin}
                              onChange={(e) => setModifierMins((prev) => ({
                                ...prev,
                                [m.id]: Math.max(1, Number(e.target.value)),
                              }))}
                              style={{ width: 48, padding: '1px 4px', border: '1px solid #ccc', borderRadius: 4, fontSize: '0.8rem' }}
                            />
                          </div>
                        )}
                      </div>
                    </div>
                  )
                })}
              </div>
            </div>
          )}

          {/* Color min / max */}
          {(item.showColors || item._rawShowColors) && (
            <div className="field" style={{ marginTop: '1rem' }}>
              <label className="label is-small">Color selection limits</label>
              <div style={{ display: 'flex', gap: 16, alignItems: 'center', flexWrap: 'wrap' }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  <label style={{ fontSize: '0.82rem', color: '#555' }}>Min colors required</label>
                  <input
                    type="number"
                    min={1}
                    value={colorMin}
                    placeholder={String(item.colorMin ?? 1)}
                    onChange={(e) => setColorMin(e.target.value)}
                    style={{ width: 60, padding: '2px 6px', border: '1px solid #ccc', borderRadius: 4, fontSize: '0.85rem' }}
                  />
                </div>
                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  <label style={{ fontSize: '0.82rem', color: '#555' }}>Max colors allowed</label>
                  <input
                    type="number"
                    min={1}
                    value={colorMax}
                    placeholder={item.colorMax != null ? String(item.colorMax) : 'unlimited'}
                    onChange={(e) => setColorMax(e.target.value)}
                    style={{ width: 80, padding: '2px 6px', border: '1px solid #ccc', borderRadius: 4, fontSize: '0.85rem' }}
                  />
                  <button
                    type="button"
                    className="button is-ghost is-small"
                    style={{ fontSize: '0.75rem', padding: '0 4px' }}
                    onClick={() => setColorMax('')}
                    title="Set to unlimited"
                  >
                    unlimited
                  </button>
                </div>
              </div>
              <p className="help">Leave max blank for unlimited. Current: min {item.colorMin ?? 1}, max {item.colorMax ?? 'unlimited'}.</p>

              {/* Chrome surcharge */}
              <div style={{ marginTop: '0.75rem', display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                <label style={{ fontSize: '0.82rem', color: '#555' }}>Chrome surcharge per color ($)</label>
                <input
                  type="number"
                  min={0}
                  step={0.01}
                  value={chromeSurcharge}
                  placeholder="0.00"
                  onChange={(e) => setChromeSurcharge(e.target.value)}
                  style={{ width: 80, padding: '2px 6px', border: '1px solid #ccc', borderRadius: 4, fontSize: '0.85rem' }}
                />
                <button
                  type="button"
                  className="button is-ghost is-small"
                  style={{ fontSize: '0.75rem', padding: '0 4px' }}
                  onClick={() => setChromeSurcharge('')}
                >
                  clear
                </button>
              </div>
              <p className="help">
                Each chrome color selected adds this amount. Leave blank (or 0) to use a flat "Chrome" Square variation instead.
                {item.chromeSurchargePerColor > 0 && ` Current: $${(item.chromeSurchargePerColor / 100).toFixed(2)}/color.`}
              </p>

              {/* Color availability */}
              <div style={{ marginTop: '0.75rem' }}>
                <button
                  type="button"
                  className="button is-small is-light"
                  onClick={() => setShowColorFilter(true)}
                >
                  🎨 Manage available colors
                  {disabledColors.length > 0 && (
                    <span style={{
                      marginLeft: 6, background: '#c07000', color: '#fff',
                      borderRadius: 999, fontSize: '0.68rem', fontWeight: 'bold',
                      padding: '1px 7px',
                    }}>
                      {disabledColors.length} hidden
                    </span>
                  )}
                </button>
              </div>
            </div>
          )}

          {showColorFilter && (
            <AdminColorFilter
              disabledColors={disabledColors}
              onSave={setDisabledColors}
              onClose={() => setShowColorFilter(false)}
            />
          )}

          {/* Quantity unit */}
          <div className="field" style={{ marginTop: '1rem' }}>
            <label className="label is-small">Quantity unit</label>
            <div className="field has-addons" style={{ maxWidth: 260 }}>
              <div className="control is-expanded">
                <input
                  className="input is-small"
                  placeholder='e.g. ft — leave blank for plain count'
                  value={quantityUnit}
                  onChange={(e) => setQuantityUnit(e.target.value)}
                />
              </div>
              {quantityUnit && (
                <div className="control">
                  <button className="button is-small" type="button" onClick={() => setQuantityUnit('')}>clear</button>
                </div>
              )}
            </div>
            <p className="help">When set, the quantity control shows "X ft" and labels itself "Length (ft)".</p>
          </div>

          {/* Images */}
          <div className="field" style={{ marginTop: item._rawModifiers.length ? '1rem' : 0 }}>
            <label className="label is-small">Images</label>

            {/* Current images */}
            {item.imageUrls.length > 0 && (
              <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginBottom: 8 }}>
                {item.imageUrls.map((url, i) => (
                  <img
                    key={i}
                    src={url}
                    alt=""
                    style={{ width: 72, height: 72, objectFit: 'cover', borderRadius: 6, border: '1px solid #ddd' }}
                  />
                ))}
              </div>
            )}

            {/* Upload */}
            <div className="file is-small">
              <label className="file-label">
                <input
                  ref={fileInputRef}
                  className="file-input"
                  type="file"
                  multiple
                  accept="image/jpeg,image/jpg,image/png,image/webp,image/gif,image/bmp,.heic,.heif"
                  onChange={handleImageUpload}
                />
                <span className="file-cta">
                  <span className="file-icon"><i className="fas fa-upload" /></span>
                  <span className="file-label">{uploading ? 'Uploading…' : 'Upload images'}</span>
                </span>
              </label>
            </div>
            <p className="help">JPEG, PNG, WEBP, GIF supported. HEIC/HEIF must be converted first.</p>

            {uploadResults.length > 0 && (
              <div style={{ marginTop: 8 }}>
                {uploadResults.map((r, i) => (
                  <p key={i} className={`help ${r.error ? 'is-danger' : 'is-success'}`}>
                    {r.name}: {r.error ?? '✓ uploaded'}
                  </p>
                ))}
              </div>
            )}
          </div>
        </div>
      </div>

      {/* Actions */}
      <div style={{ display: 'flex', gap: 8, marginTop: '0.5rem' }}>
        <button
          className={`button is-dark is-small${saving ? ' is-loading' : ''}`}
          onClick={handleSave}
          type="button"
        >
          {saved ? '✓ Saved' : 'Save changes'}
        </button>
        <button
          className="button is-small is-ghost has-text-danger"
          onClick={handleReset}
          type="button"
        >
          Reset to defaults
        </button>
        {error && <span className="has-text-danger is-size-7" style={{ alignSelf: 'center' }}>{error}</span>}
      </div>
    </div>
  )
}

// ─── Item Row ─────────────────────────────────────────────────────────────────

function ItemRow({
  item,
  categories,
  onSaved,
  onCreateCategory,
}: {
  item: AdminItem
  categories: SquareCategory[]
  onSaved: (id: string, ov: Partial<ItemOverride>) => void
  onCreateCategory: (name: string) => Promise<SquareCategory>
}) {
  const [open, setOpen] = useState(false)
  const hasOverride = Object.keys(item._override).length > 0

  return (
    <div style={{
      border: '1px solid #e0e0e0',
      borderRadius: 8,
      marginBottom: 8,
      overflow: 'hidden',
      opacity: item.hidden ? 0.5 : 1,
    }}>
      {/* Header row */}
      <div
        style={{
          display: 'flex',
          alignItems: 'center',
          gap: 12,
          padding: '0.65rem 1rem',
          cursor: 'pointer',
          backgroundColor: open ? '#f5f5f5' : '#fff',
        }}
        onClick={() => setOpen(!open)}
      >
        {/* Thumbnail */}
        <div style={{
          width: 44,
          height: 44,
          borderRadius: 6,
          overflow: 'hidden',
          flexShrink: 0,
          backgroundColor: '#f0f0f0',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
        }}>
          {item.imageUrl
            ? <img src={item.imageUrl} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
            : <i className="fas fa-image" style={{ color: '#ccc' }} />
          }
        </div>

        {/* Name + badges */}
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontWeight: 600, fontSize: '0.9rem', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
            {item.name}
            {item.hidden && (
              <span className="tag is-warning is-small" style={{ marginLeft: 8 }}>hidden</span>
            )}
            {hasOverride && !item.hidden && (
              <span className="tag is-info is-light is-small" style={{ marginLeft: 8 }}>overridden</span>
            )}
          </div>
          <div style={{ fontSize: '0.78rem', color: '#777' }}>
            {item.categoryLabel} · {cents(item.price)}
            {item.sortOrder > 0 && ` · sort: ${item.sortOrder}`}
          </div>
        </div>

        {/* Modifier count */}
        <div style={{ fontSize: '0.75rem', color: '#999', flexShrink: 0 }}>
          {item._rawModifiers.length > 0
            ? `${item.modifiers.length}/${item._rawModifiers.length} mods`
            : 'no mods'
          }
        </div>

        {/* Chevron */}
        <i className={`fas fa-chevron-${open ? 'up' : 'down'}`} style={{ color: '#aaa', fontSize: '0.75rem' }} />
      </div>

      {open && (
        <ItemEditor
          item={item}
          categories={categories}
          onSaved={onSaved}
          onCreateCategory={onCreateCategory}
        />
      )}
    </div>
  )
}

// ─── Main Page ────────────────────────────────────────────────────────────────

export default function AdminPage() {
  const router = useRouter()
  const [items,      setItems]      = useState<AdminItem[]>([])
  const [categories, setCategories] = useState<SquareCategory[]>([])
  const [loading,    setLoading]    = useState(true)
  const [error,      setError]      = useState('')
  const [search,     setSearch]     = useState('')
  const [tab,        setTab]        = useState<'items' | 'categories' | 'hours' | 'occasions' | 'delivery'>('items')
  const [fetchedAt,  setFetchedAt]  = useState<string | null>(null)
  const [refreshing, setRefreshing] = useState(false)
  const [refreshMsg, setRefreshMsg] = useState('')

  // Category creation state (for the Categories tab)
  const [newCatName,  setNewCatName]   = useState('')
  const [creatingCat, setCreatingCat]  = useState(false)
  const [catMessage,  setCatMessage]   = useState('')

  const load = useCallback(async () => {
    setLoading(true)
    setError('')
    const [itemsRes, catsRes] = await Promise.all([
      fetch(BASE + '/api/admin/items'),
      fetch(BASE + '/api/admin/categories'),
    ])
    if (itemsRes.status === 401) {
      router.push('/admin/login')
      return
    }
    if (!itemsRes.ok) {
      setError('Failed to load catalog')
      setLoading(false)
      return
    }
    const data = await itemsRes.json()
    const { categories } = catsRes.ok ? await catsRes.json() : { categories: [] }
    setItems(data.items)
    if (data.fetchedAt) setFetchedAt(data.fetchedAt)
    setCategories(categories)
    setLoading(false)
  }, [router])

  async function handleRefreshCatalog() {
    setRefreshing(true)
    setRefreshMsg('')
    const res = await fetch(BASE + '/api/admin/cache/refresh', { method: 'POST' })
    const data = await res.json()
    setRefreshing(false)
    if (res.ok) {
      setRefreshMsg(`Refreshed — ${data.itemCount} items`)
      setFetchedAt(data.fetchedAt)
      // Reload admin item list to pick up any new items
      load()
    } else {
      setRefreshMsg(`Error: ${data.error}`)
    }
  }

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

  async function handleLogout() {
    await fetch(BASE + '/api/admin/logout', { method: 'POST' })
    router.push('/admin/login')
  }

  async function handleCreateCategory(name: string): Promise<SquareCategory> {
    const res = await fetch(BASE + '/api/admin/categories', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ name }),
    })
    const data = await res.json()
    if (data.category) {
      setCategories((prev) => [...prev, data.category].sort((a, b) => a.name.localeCompare(b.name)))
    }
    return data.category ?? { id: '', name }
  }

  async function handleCreateCategoryTab() {
    if (!newCatName.trim()) return
    setCreatingCat(true)
    setCatMessage('')
    const cat = await handleCreateCategory(newCatName.trim())
    setNewCatName('')
    setCreatingCat(false)
    setCatMessage(cat.id ? `Created: ${cat.name}` : 'Failed to create category')
  }

  function handleSaved(id: string, patch: Partial<ItemOverride>) {
    setItems((prev) =>
      prev.map((item) =>
        item.id === id
          ? { ...item, _override: { ...item._override, ...patch } }
          : item
      )
    )
  }

  const q = search.trim().toLowerCase()
  const filtered = items.filter((item) =>
    !q ||
    item.name.toLowerCase().includes(q) ||
    item.categoryLabel.toLowerCase().includes(q)
  )

  return (
    <section className="section">
      <div className="container" style={{ maxWidth: 900 }}>

        {/* Header */}
        <div style={{ display: 'flex', alignItems: 'center', marginBottom: '1.5rem', gap: 12, flexWrap: 'wrap' }}>
          <div style={{ flex: 1 }}>
            <h1 className="title is-4" style={{ marginBottom: 0 }}>Admin</h1>
            <p className="has-text-grey is-size-7">Beach Party Balloons catalog management</p>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 4 }}>
            <div style={{ display: 'flex', gap: 8 }}>
              <button
                className={`button is-small is-info is-light${refreshing ? ' is-loading' : ''}`}
                onClick={handleRefreshCatalog}
                title="Re-fetch catalog from Square"
              >
                <span className="icon is-small"><i className="fas fa-cloud-download-alt" /></span>
                <span>Refresh from Square</span>
              </button>
              <button className="button is-small" onClick={load} title="Reload page data">
                <i className="fas fa-sync" />
              </button>
              <button className="button is-small" onClick={handleLogout}>Sign out</button>
            </div>
            {refreshMsg && (
              <p className={`is-size-7 ${refreshMsg.startsWith('Error') ? 'has-text-danger' : 'has-text-success'}`}>
                {refreshMsg}
              </p>
            )}
            {fetchedAt && !refreshMsg && (
              <p className="is-size-7 has-text-grey">
                Cache: {new Date(fetchedAt).toLocaleString()}
              </p>
            )}
          </div>
        </div>

        {/* Tabs */}
        <div className="tabs" style={{ marginBottom: '1rem' }}>
          <ul>
            <li className={tab === 'items' ? 'is-active' : ''}>
              <a onClick={() => setTab('items')}>Items ({items.length})</a>
            </li>
            <li className={tab === 'categories' ? 'is-active' : ''}>
              <a onClick={() => setTab('categories')}>Categories</a>
            </li>
            <li className={tab === 'hours' ? 'is-active' : ''}>
              <a onClick={() => setTab('hours')}>Hours</a>
            </li>
            <li className={tab === 'occasions' ? 'is-active' : ''}>
              <a onClick={() => setTab('occasions')}>Holidays</a>
            </li>
            <li className={tab === 'delivery' ? 'is-active' : ''}>
              <a onClick={() => setTab('delivery')}>Delivery rates</a>
            </li>
          </ul>
        </div>

        {/* Items tab */}
        {tab === 'items' && (
          <>
            {/* Search */}
            <div className="field" style={{ marginBottom: '1rem' }}>
              <div className="control has-icons-left">
                <input
                  className="input is-small"
                  type="search"
                  placeholder="Filter items…"
                  value={search}
                  onChange={(e) => setSearch(e.target.value)}
                />
                <span className="icon is-small is-left">
                  <i className="fas fa-search" />
                </span>
              </div>
            </div>

            {loading ? (
              <p className="has-text-grey">Loading catalog…</p>
            ) : error ? (
              <p className="has-text-danger">{error}</p>
            ) : filtered.length === 0 ? (
              <p className="has-text-grey">No items found.</p>
            ) : (
              <div>
                <p className="has-text-grey is-size-7" style={{ marginBottom: '0.5rem' }}>
                  {filtered.length} item{filtered.length !== 1 ? 's' : ''} · Click an item to edit
                </p>
                {filtered.map((item) => (
                  <ItemRow
                    key={item.id}
                    item={item}
                    categories={categories}
                    onSaved={handleSaved}
                    onCreateCategory={handleCreateCategory}
                  />
                ))}
              </div>
            )}
          </>
        )}

        {/* Categories tab */}
        {tab === 'categories' && (
          <div>
            <p className="has-text-grey is-size-7" style={{ marginBottom: '1rem' }}>
              These are your Square catalog categories. Creating one here adds it to Square immediately.
            </p>

            {/* Create new */}
            <div className="field has-addons" style={{ maxWidth: 400, marginBottom: '1.5rem' }}>
              <div className="control is-expanded">
                <input
                  className="input is-small"
                  placeholder="New category name"
                  value={newCatName}
                  onChange={(e) => setNewCatName(e.target.value)}
                  onKeyDown={(e) => e.key === 'Enter' && handleCreateCategoryTab()}
                />
              </div>
              <div className="control">
                <button
                  className={`button is-light is-small${creatingCat ? ' is-loading' : ''}`}
                  onClick={handleCreateCategoryTab}
                  type="button"
                >
                  Create
                </button>
              </div>
            </div>
            {catMessage && (
              <p className={`help ${catMessage.startsWith('Failed') ? 'is-danger' : 'is-success'}`} style={{ marginTop: -12, marginBottom: 12 }}>
                {catMessage}
              </p>
            )}

            {/* List */}
            {loading ? (
              <p className="has-text-grey">Loading…</p>
            ) : (
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginBottom: '2rem' }}>
                {categories.map((c) => (
                  <span key={c.id} className="tag is-medium is-light">{c.name}</span>
                ))}
              </div>
            )}

            {/* Tab display order */}
            {!loading && <CategoryDisplayEditor items={items} />}
          </div>
        )}

        {/* Hours tab */}
        {tab === 'hours' && <HoursEditor />}

        {/* Holidays tab */}
        {tab === 'occasions' && <OccasionsEditor />}

        {/* Delivery rates tab */}
        {tab === 'delivery' && <DeliveryRatesEditor />}
      </div>
    </section>
  )
}
