import { useState, useEffect } from 'react'
import { useParams, useNavigate } from 'react-router-dom'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { Save, RefreshCw, Database, Clock, BedDouble, ChevronUp, ChevronDown, Network, ShieldCheck } from 'lucide-react'
import api from '../api'

const TABS = [
  { id: 'newbook', label: 'Newbook Sync' },
  { id: 'proxy',   label: 'Scraper Proxy' },
  { id: 'parity',  label: 'Rate Parity' },
  { id: 'system',  label: 'System' },
]

interface SystemConfig {
  [key: string]: string | null
}

interface RoomCategory {
  id: number
  site_id: string
  site_name: string
  room_count: number
  is_included: boolean
  display_order: number
}

export default function Settings() {
  const { tab: tabParam } = useParams<{ tab?: string }>()
  const navigate = useNavigate()
  const qc = useQueryClient()
  const activeTab = tabParam || 'newbook'

  const { data: config, isLoading } = useQuery<SystemConfig>({
    queryKey: ['system-config'],
    queryFn: () => api.get('/competitors/config/system').then(r => r.data),
  })

  const saveMutation = useMutation({
    mutationFn: (payload: { key: string; value: string }) =>
      api.post('/competitors/config/system', payload),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['system-config'] }),
  })

  const syncNow = useMutation({
    mutationFn: () => api.post('/bookability/refresh-rates'),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['system-config'] }),
  })

  return (
    <div>
      <div className="page-header">
        <div>
          <div className="page-title">Settings</div>
          <div className="page-subtitle">Newbook sync and system configuration</div>
        </div>
      </div>

      <div className="sub-nav">
        {TABS.map(t => (
          <button
            key={t.id}
            className={`sub-nav-item${activeTab === t.id ? ' active' : ''}`}
            onClick={() => navigate(`/settings/${t.id}`)}
          >
            {t.label}
          </button>
        ))}
      </div>

      {activeTab === 'newbook' && (
        <NewbookTab
          config={config}
          isLoading={isLoading}
          onSave={(key, val) => saveMutation.mutate({ key, value: val })}
          onSyncNow={() => syncNow.mutate()}
          saving={saveMutation.isPending}
          syncing={syncNow.isPending}
        />
      )}

      {activeTab === 'proxy' && (
        <ProxyTab />
      )}

      {activeTab === 'parity' && (
        <ParityTab
          config={config}
          isLoading={isLoading}
          onSave={(key, val) => saveMutation.mutate({ key, value: val })}
          saving={saveMutation.isPending}
        />
      )}

      {activeTab === 'system' && (
        <SystemTab config={config} isLoading={isLoading} />
      )}
    </div>
  )
}

// ─── Rate Parity Tab ──────────────────────────────────────────────────────────

interface ParityCheckResult {
  status: string
  dates_compared?: number
  created?: number
  updated?: number
  resolved?: number
}

function ParityTab({ config, isLoading, onSave, saving }: {
  config: SystemConfig | undefined
  isLoading: boolean
  onSave: (key: string, value: string) => void
  saving: boolean
}) {
  const [markup, setMarkup] = useState('')
  const [markupUnit, setMarkupUnit] = useState('pct')
  const [tolerance, setTolerance] = useState('')
  const [toleranceUnit, setToleranceUnit] = useState('pct')
  const [loaded, setLoaded] = useState(false)
  const [checkResult, setCheckResult] = useState<ParityCheckResult | null>(null)

  useEffect(() => {
    if (config && !loaded) {
      setMarkup(config['parity_markup_value'] ?? config['parity_expected_markup_pct'] ?? '0')
      setMarkupUnit(config['parity_markup_unit'] ?? 'pct')
      setTolerance(config['parity_tolerance_value'] ?? config['parity_tolerance_pct'] ?? '2')
      setToleranceUnit(config['parity_tolerance_unit'] ?? 'pct')
      setLoaded(true)
    }
  }, [config, loaded])

  const enabled = (config?.['parity_check_enabled'] ?? 'true').toLowerCase() !== 'false'

  const runCheck = useMutation({
    mutationFn: () => api.post('/competitors/parity/check').then(r => r.data),
    onSuccess: (data) => setCheckResult(data),
  })

  if (isLoading) return <div className="loading-state"><div className="spinner" />Loading…</div>

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20, maxWidth: 720 }}>
      <div className="card">
        <div className="card-header">
          <ShieldCheck size={15} strokeWidth={1.75} style={{ verticalAlign: -2, marginRight: 6 }} />
          Rate Parity Check
        </div>
        <div className="card-body" style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div style={{ fontSize: 12, color: 'var(--text-mid)' }}>
            Compares our own hotel's Booking.com rate against the Newbook rate each morning (06:45).
            We deliberately price Booking.com higher to cover commission, so the check measures against
            an <strong>expected markup</strong> rather than raw equality: alert when Booking.com deviates
            from Newbook × (1 + markup) by more than the tolerance. Alerts appear on the Market View
            badge; acknowledging a date suppresses re-alerts for it, and dates that come back in line
            auto-resolve.
          </div>

          <label style={{ display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer', fontSize: 13 }}>
            <input
              type="checkbox"
              checked={enabled}
              onChange={e => onSave('parity_check_enabled', e.target.checked ? 'true' : 'false')}
              style={{ width: 15, height: 15, accentColor: 'var(--gold)' }}
            />
            Run daily parity check
          </label>

          <div>
            <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-mid)', display: 'block', marginBottom: 4 }}>
              Comparison basis
            </label>
            <select
              style={{ width: 330 }}
              value={(config?.['parity_match_mode'] ?? 'best_available')}
              onChange={e => onSave('parity_match_mode', e.target.value)}
            >
              <option value="best_available">Best available (cheapest bookable tariff on both sides)</option>
              <option value="match_terms">Match terms (flex vs flex, prepaid vs prepaid)</option>
            </select>
            <div style={{ fontSize: 11, color: 'var(--text-mid)', marginTop: 4, maxWidth: 480 }}>
              Best available compares our cheapest bookable direct tariff against the Booking.com
              lead-in rate (Booking.com's best available). Match terms instead picks the direct tariff
              with the same conditions as the scraped Booking.com rate — only differs on days where
              Booking.com's cheapest is flexible while a cheaper prepaid exists direct.
            </div>
          </div>

          <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap' }}>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-mid)', display: 'block', marginBottom: 4 }}>
                Expected Booking.com markup
              </label>
              <div style={{ display: 'flex', gap: 6 }}>
                <input
                  type="number" step="0.5" style={{ width: 110 }}
                  value={markup} onChange={e => setMarkup(e.target.value)}
                  placeholder={markupUnit === 'gbp' ? 'e.g. 20' : 'e.g. 15'}
                />
                <select style={{ width: 64 }} value={markupUnit} onChange={e => setMarkupUnit(e.target.value)}>
                  <option value="pct">%</option>
                  <option value="gbp">£</option>
                </select>
              </div>
              <div style={{ fontSize: 11, color: 'var(--text-mid)', marginTop: 4 }}>
                How much higher Booking.com should be than Newbook
                {markupUnit === 'gbp' ? ' (flat £ per night)' : ' (percentage)'}.
              </div>
            </div>
            <div>
              <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-mid)', display: 'block', marginBottom: 4 }}>
                Tolerance (±)
              </label>
              <div style={{ display: 'flex', gap: 6 }}>
                <input
                  type="number" step="0.5" style={{ width: 110 }}
                  value={tolerance} onChange={e => setTolerance(e.target.value)}
                  placeholder={toleranceUnit === 'gbp' ? 'e.g. 5' : 'e.g. 2'}
                />
                <select style={{ width: 64 }} value={toleranceUnit} onChange={e => setToleranceUnit(e.target.value)}>
                  <option value="pct">%</option>
                  <option value="gbp">£</option>
                </select>
              </div>
              <div style={{ fontSize: 11, color: 'var(--text-mid)', marginTop: 4 }}>
                Allowed deviation from expected before alerting.
              </div>
            </div>
          </div>

          <div style={{ padding: '8px 12px', background: '#f8fafc', borderRadius: 6, fontSize: 12, color: 'var(--text-mid)' }}>
            Rule: alert when Booking.com ≠ Newbook {markupUnit === 'gbp' ? `+ £${markup || '0'}` : `+ ${markup || '0'}%`}
            {' '}beyond ±{toleranceUnit === 'gbp' ? `£${tolerance || '0'}` : `${tolerance || '0'}%`}.
            {' '}Example: Newbook £100 → expect £{(markupUnit === 'gbp'
              ? 100 + (parseFloat(markup) || 0)
              : 100 * (1 + (parseFloat(markup) || 0) / 100)).toFixed(0)},
            {' '}alert outside £{(() => {
              const exp = markupUnit === 'gbp' ? 100 + (parseFloat(markup) || 0) : 100 * (1 + (parseFloat(markup) || 0) / 100)
              const tol = toleranceUnit === 'gbp' ? (parseFloat(tolerance) || 0) : exp * (parseFloat(tolerance) || 0) / 100
              return `${(exp - tol).toFixed(0)}–£${(exp + tol).toFixed(0)}`
            })()}.
          </div>

          <div style={{ display: 'flex', gap: 8 }}>
            <button
              className="btn btn-primary"
              disabled={saving}
              onClick={() => {
                onSave('parity_markup_value', markup || '0')
                onSave('parity_markup_unit', markupUnit)
                onSave('parity_tolerance_value', tolerance || '2')
                onSave('parity_tolerance_unit', toleranceUnit)
              }}
            >
              <Save size={13} strokeWidth={1.75} />
              Save
            </button>
            <button
              className="btn btn-outline"
              disabled={runCheck.isPending}
              onClick={() => runCheck.mutate()}
            >
              <RefreshCw size={13} strokeWidth={1.75} />
              {runCheck.isPending ? 'Checking…' : 'Run check now'}
            </button>
          </div>

          {checkResult && (
            <div style={{ padding: '10px 14px', background: '#f0fdf4', borderRadius: 8, border: '1px solid #bbf7d0', fontSize: 13 }}>
              {checkResult.status === 'disabled'
                ? 'Check is disabled — enable it above first.'
                : `Compared ${checkResult.dates_compared} dates — ${checkResult.created} new alerts, ${checkResult.updated} updated, ${checkResult.resolved} resolved.`}
            </div>
          )}
        </div>
      </div>
    </div>
  )
}

// ─── Scraper Proxy Tab ────────────────────────────────────────────────────────

interface ProxyConfigData {
  enabled: boolean
  host: string
  port: string
  username: string
  country: string
  password_set: boolean
}

interface ProxyTestResult {
  ok: boolean
  ip: string
  country: string
  city: string
  org: string
}

function ProxyTab() {
  const qc = useQueryClient()

  const { data: cfg, isLoading } = useQuery<ProxyConfigData>({
    queryKey: ['proxy-config'],
    queryFn: () => api.get('/competitors/config/proxy').then(r => r.data),
  })

  const [enabled, setEnabled] = useState(false)
  const [host, setHost] = useState('')
  const [port, setPort] = useState('823')
  const [username, setUsername] = useState('')
  const [country, setCountry] = useState('gb')
  const [password, setPassword] = useState('')
  const [testResult, setTestResult] = useState<ProxyTestResult | null>(null)
  const [testError, setTestError] = useState<string | null>(null)
  const [workers, setWorkers] = useState('3')

  const { data: sysCfg } = useQuery<SystemConfig>({
    queryKey: ['system-config'],
    queryFn: () => api.get('/competitors/config/system').then(r => r.data),
  })

  // Seed form once the stored config arrives (password stays blank by design)
  useEffect(() => {
    if (cfg) {
      setEnabled(cfg.enabled)
      setHost(cfg.host)
      setPort(cfg.port)
      setUsername(cfg.username)
      setCountry(cfg.country)
    }
  }, [cfg])

  useEffect(() => {
    if (sysCfg?.booking_scraper_concurrency) setWorkers(String(sysCfg.booking_scraper_concurrency))
  }, [sysCfg])

  const saveWorkers = useMutation({
    mutationFn: () => api.post('/competitors/config/system', {
      key: 'booking_scraper_concurrency', value: String(Math.max(1, parseInt(workers) || 1)),
    }),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['system-config'] }),
  })

  const save = useMutation({
    mutationFn: () =>
      api.post('/competitors/config/proxy', {
        enabled, host, port, username, country,
        // Only send a password when the user typed a new one
        password: password || undefined,
      }),
    onSuccess: () => {
      setPassword('')
      qc.invalidateQueries({ queryKey: ['proxy-config'] })
      qc.invalidateQueries({ queryKey: ['system-config'] })
    },
  })

  const runTest = useMutation({
    mutationFn: () => api.post('/competitors/config/proxy/test').then(r => r.data as ProxyTestResult),
    onMutate: () => { setTestResult(null); setTestError(null) },
    onSuccess: (data) => setTestResult(data),
    onError: (err: any) => setTestError(err?.response?.data?.detail || 'Test failed'),
  })

  if (isLoading) {
    return <div className="loading-state"><div className="spinner" /> Loading…</div>
  }

  const labelStyle: React.CSSProperties = {
    fontSize: 12, fontWeight: 600, color: 'var(--text-mid)', display: 'block', marginBottom: 6,
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20, maxWidth: 600 }}>
      <div className="card">
        <div className="card-header">
          <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <Network size={16} strokeWidth={1.75} />
            Residential Proxy
          </span>
          <span className={`badge ${enabled ? 'badge-success' : 'badge-neutral'}`}>
            {enabled ? 'Enabled' : 'Disabled'}
          </span>
        </div>
        <div className="card-body" style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <p style={{ fontSize: 13, color: 'var(--text-mid)', margin: 0 }}>
            Routes the Booking.com scraper through a residential proxy (e.g. DataImpulse).
            One sticky IP is held per scrape session and rotated automatically if a page is
            blocked. Leave disabled to scrape from this server's own IP.
          </p>

          <label style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13 }}>
            <input type="checkbox" checked={enabled} onChange={e => setEnabled(e.target.checked)} />
            Enable proxy for scraping
          </label>

          <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 12 }}>
            <div>
              <label style={labelStyle}>Proxy host</label>
              <input type="text" placeholder="gw.dataimpulse.com" value={host}
                onChange={e => setHost(e.target.value)} style={{ width: '100%' }} />
            </div>
            <div>
              <label style={labelStyle}>Port</label>
              <input type="text" placeholder="823" value={port}
                onChange={e => setPort(e.target.value)} style={{ width: '100%' }} />
            </div>
          </div>

          <div>
            <label style={labelStyle}>Username / login</label>
            <input type="text" placeholder="account login" value={username}
              onChange={e => setUsername(e.target.value)} style={{ width: '100%' }} />
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: '2fr 1fr', gap: 12 }}>
            <div>
              <label style={labelStyle}>Password</label>
              <input type="password" placeholder={cfg?.password_set ? '•••••••• (unchanged)' : 'not set'}
                value={password} onChange={e => setPassword(e.target.value)} style={{ width: '100%' }} />
            </div>
            <div>
              <label style={labelStyle}>Country</label>
              <input type="text" placeholder="gb" value={country}
                onChange={e => setCountry(e.target.value.toLowerCase())} style={{ width: '100%' }} />
            </div>
          </div>

          <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
            <button className="btn btn-primary" onClick={() => save.mutate()} disabled={save.isPending}>
              <Save size={14} strokeWidth={1.75} />
              {save.isPending ? 'Saving…' : 'Save'}
            </button>
            <button className="btn btn-outline" onClick={() => runTest.mutate()} disabled={runTest.isPending}>
              <ShieldCheck size={14} strokeWidth={1.75} />
              {runTest.isPending ? 'Testing…' : 'Test Connection'}
            </button>
          </div>

          {save.isError && (
            <p style={{ fontSize: 13, color: 'var(--danger)', margin: 0 }}>
              {(save.error as any)?.response?.data?.detail || 'Save failed'}
            </p>
          )}
          {testResult && (
            <div style={{ fontSize: 13, color: 'var(--success)', background: 'var(--bg-subtle, #f0fdf4)',
              padding: '10px 12px', borderRadius: 6, border: '1px solid var(--success)' }}>
              ✓ Connected — exit IP <strong>{testResult.ip}</strong> ({testResult.country}
              {testResult.city ? `, ${testResult.city}` : ''}){testResult.org ? ` · ${testResult.org}` : ''}
            </div>
          )}
          {testError && (
            <p style={{ fontSize: 13, color: 'var(--danger)', margin: 0 }}>{testError}</p>
          )}
        </div>
      </div>

      <div className="card">
        <div className="card-header">
          <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <Network size={16} strokeWidth={1.75} />
            Parallel Workers
          </span>
        </div>
        <div className="card-body" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <p style={{ fontSize: 13, color: 'var(--text-mid)', margin: 0 }}>
            How many dates to scrape at once. Each worker runs its own browser on its own
            residential IP, so a run finishes roughly this many times faster. Only takes effect
            when the proxy is enabled (without it, all workers would share one IP). Budget about
            0.4&nbsp;GB of RAM per worker — 3 is safe on the current 4&nbsp;GB; raise it after
            adding RAM.
          </p>
          <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
            <input type="number" min={1} max={12} value={workers}
              onChange={e => setWorkers(e.target.value)} style={{ width: 90 }} />
            <button className="btn btn-primary btn-sm" onClick={() => saveWorkers.mutate()}
              disabled={saveWorkers.isPending}>
              <Save size={13} strokeWidth={1.75} />
              {saveWorkers.isPending ? 'Saving…' : 'Save'}
            </button>
            {!enabled && (
              <span style={{ fontSize: 12, color: 'var(--warning)' }}>
                Enable the proxy above for this to apply
              </span>
            )}
          </div>
        </div>
      </div>
    </div>
  )
}

// ─── Newbook Sync Tab ─────────────────────────────────────────────────────────

interface NewbookTabProps {
  config: SystemConfig | undefined
  isLoading: boolean
  onSave: (key: string, val: string) => void
  onSyncNow: () => void
  saving: boolean
  syncing: boolean
}

function NewbookTab({ config, isLoading, onSave, onSyncNow, saving, syncing }: NewbookTabProps) {
  const [syncTime, setSyncTime] = useState('')

  const syncEnabled = config?.sync_newbook_current_rates_enabled === 'true'
  const currentTime = config?.sync_newbook_current_rates_time || '05:20'

  if (isLoading) {
    return <div className="loading-state"><div className="spinner" /> Loading…</div>
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 20, maxWidth: 600 }}>
      <div className="card">
        <div className="card-header">
          <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <Database size={16} strokeWidth={1.75} />
            Newbook Rates Sync
          </span>
          <span className={`badge ${syncEnabled ? 'badge-success' : 'badge-neutral'}`}>
            {syncEnabled ? 'Enabled' : 'Disabled'}
          </span>
        </div>
        <div className="card-body" style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <p style={{ fontSize: 13, color: 'var(--text-mid)', margin: 0 }}>
            When enabled, the app fetches current tariff rates from the Newbook API daily and
            stores them for the Bookability view and rate parity calculations.
          </p>

          <div style={{ display: 'flex', gap: 12 }}>
            <button
              className={`btn ${syncEnabled ? 'btn-outline' : 'btn-primary'}`}
              onClick={() => onSave('sync_newbook_current_rates_enabled', syncEnabled ? 'false' : 'true')}
              disabled={saving}
            >
              {syncEnabled ? 'Disable Sync' : 'Enable Sync'}
            </button>
            <button
              className="btn btn-outline"
              onClick={onSyncNow}
              disabled={syncing}
            >
              <RefreshCw size={14} strokeWidth={1.75} />
              {syncing ? 'Refreshing…' : 'Sync Now'}
            </button>
          </div>
        </div>
      </div>

      <div className="card">
        <div className="card-header">
          <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <Clock size={16} strokeWidth={1.75} />
            Sync Schedule
          </span>
        </div>
        <div className="card-body" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div>
            <label style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-mid)', display: 'block', marginBottom: 6 }}>
              Daily sync time (HH:MM)
            </label>
            <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
              <input
                type="time"
                style={{ width: 130 }}
                defaultValue={currentTime}
                onChange={e => setSyncTime(e.target.value)}
              />
              <button
                className="btn btn-primary btn-sm"
                onClick={() => syncTime && onSave('sync_newbook_current_rates_time', syncTime)}
                disabled={saving || !syncTime}
              >
                <Save size={13} strokeWidth={1.75} />
                Save
              </button>
            </div>
            <p style={{ fontSize: 12, color: 'var(--text-mid)', marginTop: 6 }}>
              Current: {currentTime} — Booking.com scraper runs at {config?.booking_scraper_daily_time || '05:30'}
            </p>
          </div>
        </div>
      </div>

      <RoomCategoriesCard />
    </div>
  )
}

// ─── Room Categories ──────────────────────────────────────────────────────────

function RoomCategoriesCard() {
  const qc = useQueryClient()

  const { data: categories, isLoading } = useQuery<RoomCategory[]>({
    queryKey: ['room-categories'],
    queryFn: () => api.get('/bookability/categories').then(r => r.data),
  })

  const syncCategories = useMutation({
    mutationFn: () => api.post('/bookability/categories/sync'),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['room-categories'] }),
  })

  const toggleCategory = useMutation({
    mutationFn: ({ id, included }: { id: number; included: boolean }) =>
      api.patch(`/bookability/categories/${id}`, { is_included: included }),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['room-categories'] }),
  })

  const reorderCategories = useMutation({
    mutationFn: (ordered: RoomCategory[]) =>
      Promise.all(ordered.map((cat, idx) =>
        api.patch(`/bookability/categories/${cat.id}`, { display_order: (idx + 1) * 10 })
      )),
    onSuccess: () => qc.invalidateQueries({ queryKey: ['room-categories'] }),
  })

  const moveCategory = (idx: number, dir: -1 | 1) => {
    if (!categories) return
    const target = idx + dir
    if (target < 0 || target >= categories.length) return
    const reordered = [...categories]
    ;[reordered[idx], reordered[target]] = [reordered[target], reordered[idx]]
    reorderCategories.mutate(reordered)
  }

  return (
    <div className="card">
      <div className="card-header">
        <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <BedDouble size={16} strokeWidth={1.75} />
          Room Categories
        </span>
        <button
          className="btn btn-outline btn-sm"
          onClick={() => syncCategories.mutate()}
          disabled={syncCategories.isPending}
        >
          <RefreshCw size={13} strokeWidth={1.75} />
          {syncCategories.isPending ? 'Fetching…' : 'Fetch from Newbook'}
        </button>
      </div>
      <div className="card-body" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
        <p style={{ fontSize: 13, color: 'var(--text-mid)', margin: 0 }}>
          Rate syncs only fetch tariffs for the included categories below. If the list is
          empty, fetch categories from Newbook first — otherwise syncs will do nothing.
        </p>
        {syncCategories.isError && (
          <p style={{ fontSize: 13, color: 'var(--danger)', margin: 0 }}>
            {(syncCategories.error as any)?.response?.data?.detail || 'Category fetch failed'}
          </p>
        )}
        {isLoading ? (
          <div className="loading-state"><div className="spinner" /> Loading…</div>
        ) : !categories?.length ? (
          <p style={{ fontSize: 13, color: 'var(--warning)', margin: 0 }}>
            No room categories yet — click “Fetch from Newbook” to load them.
          </p>
        ) : (
          <div className="table-wrap">
            <table>
              <thead>
                <tr>
                  <th>Included</th>
                  <th>Category</th>
                  <th>Rooms</th>
                  <th>Order</th>
                </tr>
              </thead>
              <tbody>
                {categories.map((cat, idx) => (
                  <tr key={cat.id}>
                    <td>
                      <input
                        type="checkbox"
                        checked={cat.is_included}
                        onChange={e => toggleCategory.mutate({ id: cat.id, included: e.target.checked })}
                        disabled={toggleCategory.isPending}
                      />
                    </td>
                    <td>{cat.site_name}</td>
                    <td>{cat.room_count}</td>
                    <td>
                      <span style={{ display: 'inline-flex', gap: 4 }}>
                        <button
                          className="btn btn-outline btn-sm"
                          style={{ padding: '2px 6px' }}
                          onClick={() => moveCategory(idx, -1)}
                          disabled={idx === 0 || reorderCategories.isPending}
                          title="Move up"
                        >
                          <ChevronUp size={13} strokeWidth={1.75} />
                        </button>
                        <button
                          className="btn btn-outline btn-sm"
                          style={{ padding: '2px 6px' }}
                          onClick={() => moveCategory(idx, 1)}
                          disabled={idx === categories.length - 1 || reorderCategories.isPending}
                          title="Move down"
                        >
                          <ChevronDown size={13} strokeWidth={1.75} />
                        </button>
                      </span>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </div>
    </div>
  )
}

// ─── System Tab ───────────────────────────────────────────────────────────────

function SystemTab({ config, isLoading }: { config: SystemConfig | undefined; isLoading: boolean }) {
  if (isLoading) {
    return <div className="loading-state"><div className="spinner" /> Loading…</div>
  }

  const displayKeys = [
    'booking_scraper_enabled',
    'booking_scraper_backend',
    'booking_scraper_daily_time',
    'booking_proxy_enabled',
    'booking_proxy_host',
    'booking_proxy_country',
    'booking_scraper_concurrency',
    'sync_newbook_current_rates_enabled',
    'sync_newbook_current_rates_time',
  ]

  return (
    <div style={{ maxWidth: 700 }}>
      <div className="card">
        <div className="card-header">System Configuration</div>
        <div className="table-wrap">
          <table>
            <thead>
              <tr>
                <th>Key</th>
                <th>Value</th>
              </tr>
            </thead>
            <tbody>
              {displayKeys.map(k => (
                <tr key={k}>
                  <td><code style={{ fontSize: 12, color: 'var(--text-mid)' }}>{k}</code></td>
                  <td>
                    <span style={{ fontSize: 13 }}>
                      {config?.[k] ?? <em style={{ color: 'var(--text-mid)' }}>not set</em>}
                    </span>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      <div style={{ marginTop: 16, fontSize: 12, color: 'var(--text-mid)' }}>
        To configure the Booking.com scraper location and hotel tiers, use the Settings tab inside{' '}
        <a href="/rates/market" style={{ color: 'var(--gold)' }}>Market View</a>.
      </div>
    </div>
  )
}
