import React from 'react'
import { Head, Link, useForm, usePage } from '@inertiajs/react'
import AdminLayout from '../../../Layouts/AdminLayout'
import HomepageAnnouncement from '../../../components/homepage/HomepageAnnouncement'
import HomepageAnnouncementEditor from '../../../components/homepage/HomepageAnnouncementEditor'
import Checkbox from '../../../components/ui/Checkbox'
import DateTimePicker from '../../../components/ui/DateTimePicker'
import NovaSelect from '../../../components/ui/NovaSelect'
import ShareToast from '../../../components/ui/ShareToast'

const BACKGROUND_IMAGE_ACCEPT = 'image/jpeg,image/jpg,image/png,image/webp'
const BACKGROUND_IMAGE_MAX_BYTES = 5 * 1024 * 1024

const FORM_TABS = [
  { id: 'overview', label: 'Overview', description: 'Identity, status, and schedule.' },
  { id: 'content', label: 'Content', description: 'Message body and CTA links.' },
  { id: 'design', label: 'Design', description: 'Visual treatment and background media.' },
  { id: 'behavior', label: 'Behavior', description: 'Dismiss rules and placement.' },
]

const FIELD_TAB_MAP = {
  title: 'overview',
  badge_text: 'overview',
  subtitle: 'overview',
  type: 'overview',
  status: 'overview',
  priority: 'overview',
  is_active: 'overview',
  starts_at: 'overview',
  ends_at: 'overview',
  content_html: 'content',
  primary_link_label: 'content',
  primary_link_type: 'content',
  primary_link_url: 'content',
  primary_link_target_id: 'content',
  secondary_link_label: 'content',
  secondary_link_type: 'content',
  secondary_link_url: 'content',
  secondary_link_target_id: 'content',
  gradient_preset: 'design',
  theme_preset: 'design',
  overlay_opacity: 'design',
  background_image: 'design',
  background_image_file: 'design',
  remove_background_image: 'design',
  dismiss_version: 'behavior',
  placement: 'behavior',
  is_dismissible: 'behavior',
}

function isIntegerLike(value) {
  if (typeof value === 'number') return Number.isInteger(value)
  if (typeof value !== 'string') return false
  const normalized = value.trim()
  return normalized !== '' && /^-?\d+$/.test(normalized)
}

function isSafeClientUrl(value) {
  const normalized = String(value || '').trim()
  if (!normalized) return true
  return normalized.startsWith('/') || normalized.startsWith('https://')
}

function firstErrorMessage(errors) {
  const firstKey = Object.keys(errors || {})[0]
  if (!firstKey) return null
  const value = errors[firstKey]
  return Array.isArray(value) ? value[0] : value
}

function getCsrfToken() {
  if (typeof document === 'undefined') return ''
  return document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''
}

function FieldError({ error }) {
  if (!error) return null
  return <p className="text-xs text-rose-300">{error}</p>
}

function resolveTabFromErrors(errors) {
  const firstKey = Object.keys(errors || {})[0]
  return FIELD_TAB_MAP[firstKey] || 'overview'
}

function Section({ title, description, children }) {
  return (
    <section className="rounded-[30px] border border-white/10 bg-white/[0.03] p-6">
      <div className="mb-5">
        <h2 className="text-lg font-semibold text-white">{title}</h2>
        {description ? <p className="mt-1 text-sm text-slate-400">{description}</p> : null}
      </div>
      <div className="grid gap-5">{children}</div>
    </section>
  )
}

function TextField({ label, value, onChange, error, ...rest }) {
  return (
    <label className="grid gap-2 text-sm text-slate-200">
      <span>{label}</span>
      <input value={value} onChange={onChange} className="rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" {...rest} />
      <FieldError error={error} />
    </label>
  )
}

function ToggleField({ label, checked, onChange, help }) {
  return (
    <div className="rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-sm text-slate-200">
      <div>
        <div className="font-semibold text-white">{label}</div>
        {help ? <div className="mt-1 text-xs leading-6 text-slate-400">{help}</div> : null}
      </div>
      <div className="mt-3">
        <Checkbox checked={checked} onChange={onChange} aria-label={label} variant="sky" size={20} />
      </div>
    </div>
  )
}

function SelectField({ label, value, onChange, options, error }) {
  return (
    <NovaSelect
      label={label}
      value={value}
      onChange={onChange}
      options={options || []}
      error={error}
      searchable={false}
      className="rounded-2xl bg-black/20"
    />
  )
}

function DateTimeField({ label, value, onChange, error }) {
  return (
    <DateTimePicker
      label={label}
      value={value}
      onChange={onChange}
      error={error}
      clearable
      className="rounded-2xl bg-black/20"
    />
  )
}

function BackgroundImageDropzone({ previewUrl, storedValue, selectedFileName, error, onSelect }) {
  const inputRef = React.useRef(null)
  const [dragging, setDragging] = React.useState(false)

  const handleFile = React.useCallback((file) => {
    onSelect?.(file || null)
  }, [onSelect])

  return (
    <div className="grid gap-3 text-sm text-slate-200">
      <div className="flex items-center justify-between gap-3">
        <span>Upload background image</span>
        <button
          type="button"
          onClick={() => inputRef.current?.click()}
          className="rounded-full border border-white/10 bg-white/[0.04] px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.14em] text-white transition hover:bg-white/[0.08]"
        >
          Browse
        </button>
      </div>

      <div
        role="button"
        tabIndex={0}
        onClick={() => inputRef.current?.click()}
        onKeyDown={(event) => {
          if (event.key === 'Enter' || event.key === ' ') {
            event.preventDefault()
            inputRef.current?.click()
          }
        }}
        onDragOver={(event) => {
          event.preventDefault()
          setDragging(true)
        }}
        onDragEnter={(event) => {
          event.preventDefault()
          setDragging(true)
        }}
        onDragLeave={(event) => {
          event.preventDefault()
          setDragging(false)
        }}
        onDrop={(event) => {
          event.preventDefault()
          setDragging(false)
          handleFile(event.dataTransfer?.files?.[0] || null)
        }}
        className={[
          'rounded-[28px] border border-dashed px-5 py-5 transition outline-none',
          dragging
            ? 'border-sky-300/50 bg-sky-400/12'
            : 'border-white/10 bg-black/20 hover:border-white/20 hover:bg-white/[0.04]',
        ].join(' ')}
      >
        <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
          <div className="flex items-start gap-4">
            <div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl border border-sky-300/20 bg-sky-400/10 text-sky-100">
              <i className="fa-solid fa-cloud-arrow-up" />
            </div>
            <div>
              <div className="text-sm font-semibold text-white">Drop image here or browse</div>
              <div className="mt-1 text-xs leading-5 text-slate-400">JPG, PNG, or WEBP. Maximum 5 MB. The selected image is previewed here and on the card preview.</div>
              <div className="mt-2 flex flex-wrap gap-2 text-[11px] text-slate-400">
                <span className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1">JPG</span>
                <span className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1">PNG</span>
                <span className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1">WEBP</span>
                <span className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1">Max 5 MB</span>
              </div>
            </div>
          </div>

          <div className="h-28 w-full overflow-hidden rounded-[20px] border border-white/10 bg-slate-950 lg:w-44">
            {previewUrl ? (
              <img src={previewUrl} alt="Background preview" className="h-full w-full object-cover" />
            ) : (
              <div className="flex h-full items-center justify-center px-4 text-center text-sm text-slate-500">No background image selected</div>
            )}
          </div>
        </div>

        {selectedFileName ? <div className="mt-4 truncate rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-xs text-slate-300">Selected file: <span className="text-white">{selectedFileName}</span></div> : null}
        {!selectedFileName && storedValue ? <div className="mt-4 truncate rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-xs text-slate-400">Stored path: <span className="text-slate-200">{storedValue}</span></div> : null}
        {error ? <div className="mt-3 rounded-2xl border border-rose-300/20 bg-rose-400/10 px-4 py-3 text-sm text-rose-100">{error}</div> : null}

        <input
          ref={inputRef}
          type="file"
          accept={BACKGROUND_IMAGE_ACCEPT}
          className="hidden"
          onChange={(event) => {
            handleFile(event.target.files?.[0] || null)
            event.target.value = ''
          }}
        />
      </div>
    </div>
  )
}

function LinkFields({ title, prefix, form, options }) {
  return (
    <div className="grid gap-4 rounded-[28px] border border-white/10 bg-black/20 p-4">
      <h3 className="text-sm font-semibold uppercase tracking-[0.18em] text-white/75">{title}</h3>
      <div className="grid gap-4 md:grid-cols-2">
        <TextField label="Label" value={form.data[`${prefix}_link_label`]} onChange={(event) => form.setData(`${prefix}_link_label`, event.target.value)} error={form.errors[`${prefix}_link_label`]} maxLength={80} />
        <SelectField label="Link type" value={form.data[`${prefix}_link_type`]} onChange={(nextValue) => form.setData(`${prefix}_link_type`, nextValue)} options={options.linkTypes} error={form.errors[`${prefix}_link_type`]} />
      </div>
      <div className="grid gap-4 md:grid-cols-2">
        <TextField label="Fallback URL" value={form.data[`${prefix}_link_url`]} onChange={(event) => form.setData(`${prefix}_link_url`, event.target.value)} error={form.errors[`${prefix}_link_url`]} placeholder="/explore or https://example.com" maxLength={2048} />
        <TextField label="Target ID" value={form.data[`${prefix}_link_target_id`]} onChange={(event) => form.setData(`${prefix}_link_target_id`, event.target.value)} error={form.errors[`${prefix}_link_target_id`]} placeholder="Optional entity id" inputMode="numeric" />
      </div>
    </div>
  )
}

export default function HomepageAnnouncementForm({ announcement, previewAnnouncement, options, submitUrl, previewUrl, indexUrl, destroyUrl }) {
  const { props } = usePage()
  const isEditing = Boolean(announcement?.id)
  const flash = props.flash ?? {}
  const [activeTab, setActiveTab] = React.useState('overview')
  const [preview, setPreview] = React.useState(previewAnnouncement || null)
  const [previewBusy, setPreviewBusy] = React.useState(false)
  const [previewError, setPreviewError] = React.useState('')
  const [backgroundImageError, setBackgroundImageError] = React.useState('')
  const [backgroundPreviewUrl, setBackgroundPreviewUrl] = React.useState(announcement?.background_image_url || '')
  const [toast, setToast] = React.useState({ id: 0, visible: false, message: '', variant: 'success' })

  const form = useForm({
    ...announcement,
    background_image_file: null,
  })

  const showToast = React.useCallback((message, variant = 'success') => {
    setToast({
      id: Date.now(),
      visible: true,
      message,
      variant,
    })
  }, [])

  React.useEffect(() => {
    return () => {
      if (backgroundPreviewUrl?.startsWith?.('blob:')) {
        URL.revokeObjectURL(backgroundPreviewUrl)
      }
    }
  }, [backgroundPreviewUrl])

  const previewWithLocalImage = React.useMemo(() => {
    if (!preview) return null
    if (!backgroundPreviewUrl) return preview
    return { ...preview, background_image_url: backgroundPreviewUrl }
  }, [backgroundPreviewUrl, preview])

  const validateForm = React.useCallback((statusOverride = null) => {
    const data = { ...form.data, status: statusOverride || form.data.status }
    const errors = []

    if (!String(data.title || '').trim()) {
      errors.push('Title is required.')
    }

    if (!String(data.type || '').trim()) {
      errors.push('Type is required.')
    }

    if (!String(data.status || '').trim()) {
      errors.push('Status is required.')
    }

    if (!String(data.placement || '').trim()) {
      errors.push('Placement is required.')
    }

    if (!isIntegerLike(data.priority)) {
      errors.push('Priority must be a whole number.')
    }

    if (!isIntegerLike(data.dismiss_version) || Number(data.dismiss_version) < 1) {
      errors.push('Dismiss version must be a whole number greater than or equal to 1.')
    }

    if (String(data.overlay_opacity || '').trim() !== '' && (!isIntegerLike(data.overlay_opacity) || Number(data.overlay_opacity) < 0 || Number(data.overlay_opacity) > 100)) {
      errors.push('Overlay opacity must be a whole number between 0 and 100.')
    }

    if (data.starts_at && Number.isNaN(Date.parse(data.starts_at))) {
      errors.push('Starts at must be a valid date and time.')
    }

    if (data.ends_at && Number.isNaN(Date.parse(data.ends_at))) {
      errors.push('Ends at must be a valid date and time.')
    }

    if (data.starts_at && data.ends_at && Date.parse(data.ends_at) < Date.parse(data.starts_at)) {
      errors.push('Ends at must be after or equal to starts at.')
    }

    for (const prefix of ['primary', 'secondary']) {
      const type = String(data[`${prefix}_link_type`] || 'none')
      const label = String(data[`${prefix}_link_label`] || '').trim()
      const url = String(data[`${prefix}_link_url`] || '').trim()
      const targetId = data[`${prefix}_link_target_id`]

      if (type !== 'none' && !label) {
        errors.push(`${prefix === 'primary' ? 'Primary' : 'Secondary'} CTA label is required when that link is enabled.`)
      }

      if (url && !isSafeClientUrl(url)) {
        errors.push(`${prefix === 'primary' ? 'Primary' : 'Secondary'} CTA URL must start with / or https://.`)
      }

      if (type === 'custom_url' && !url) {
        errors.push(`${prefix === 'primary' ? 'Primary' : 'Secondary'} custom CTA requires a URL.`)
      }

      if (!['none', 'custom_url', 'explore', 'upload'].includes(type) && !url) {
        if (String(targetId || '').trim() === '') {
          errors.push(`${prefix === 'primary' ? 'Primary' : 'Secondary'} CTA requires a target id or fallback URL.`)
        } else if (!isIntegerLike(targetId) || Number(targetId) < 1) {
          errors.push(`${prefix === 'primary' ? 'Primary' : 'Secondary'} target id must be a whole number greater than or equal to 1.`)
        }
      }
    }

    return errors
  }, [form.data])

  const applyBackgroundFile = React.useCallback((file) => {
    setBackgroundImageError('')

    if (!file) {
      form.setData('background_image_file', null)
      return
    }

    const fileType = String(file.type || '').toLowerCase()
    const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp']

    if (!allowedTypes.includes(fileType)) {
      setBackgroundImageError('Use a JPG, PNG, or WEBP image for the announcement background.')
      return
    }

    if (file.size > BACKGROUND_IMAGE_MAX_BYTES) {
      setBackgroundImageError('Background images must be 5 MB or smaller.')
      return
    }

    form.setData('background_image_file', file)
    form.setData('remove_background_image', false)

    if (backgroundPreviewUrl?.startsWith?.('blob:')) {
      URL.revokeObjectURL(backgroundPreviewUrl)
    }

    setBackgroundPreviewUrl(URL.createObjectURL(file))
  }, [backgroundPreviewUrl, form])

  const submit = (statusOverride = null) => {
    const validationErrors = validateForm(statusOverride)
    if (validationErrors.length > 0) {
      showToast(validationErrors[0], 'error')
      return
    }

    form.transform((data) => {
      const payload = { ...data, status: statusOverride || data.status }
      if (isEditing) payload._method = 'patch'
      return payload
    })

    form.post(submitUrl, {
      forceFormData: true,
      preserveScroll: true,
      onError: (errors) => {
        setActiveTab(resolveTabFromErrors(errors))
        const message = firstErrorMessage(errors) || 'Please correct the form and try again.'
        showToast(message, 'error')
      },
      onSuccess: () => {
        showToast(isEditing ? 'Homepage announcement updated.' : 'Homepage announcement created.', 'success')
      },
      onFinish: () => form.transform((data) => data),
    })
  }

  const runPreview = async () => {
    const validationErrors = validateForm()
    if (validationErrors.length > 0) {
      const message = validationErrors[0]
      setPreviewError(message)
      showToast(message, 'error')
      return
    }

    setPreviewBusy(true)
    setPreviewError('')

    try {
      const formData = new FormData()
      const payload = form.data

      Object.entries(payload).forEach(([key, value]) => {
        if (value === null || value === undefined || key === 'id') return
        if (value instanceof File) {
          formData.append(key, value)
          return
        }
        formData.append(key, String(value))
      })

      const response = await fetch(previewUrl, {
        method: 'POST',
        credentials: 'same-origin',
        headers: {
          'X-CSRF-TOKEN': getCsrfToken(),
          'X-Requested-With': 'XMLHttpRequest',
          Accept: 'application/json',
        },
        body: formData,
      })

      const body = await response.json().catch(() => ({}))
      if (!response.ok) {
        throw new Error(body?.message || 'Preview failed.')
      }

      setPreview(body.announcement || null)
    } catch (error) {
      const message = error.message || 'Preview failed.'
      setPreviewError(message)
      showToast(message, 'error')
    } finally {
      setPreviewBusy(false)
    }
  }

  return (
    <AdminLayout title={isEditing ? 'Edit Homepage Announcement' : 'Create Homepage Announcement'} subtitle="Compose, schedule, preview, and publish a premium homepage announcement card.">
      <Head title={isEditing ? 'Admin · Edit Homepage Announcement' : 'Admin · Create Homepage Announcement'} />
      <ShareToast
        key={toast.id}
        message={toast.message}
        visible={toast.visible}
        variant={toast.variant}
        duration={toast.variant === 'error' ? 3200 : 2200}
        onHide={() => setToast((current) => ({ ...current, visible: false }))}
      />

      {flash.success ? <div className="mb-6 rounded-2xl border border-emerald-300/20 bg-emerald-300/10 px-4 py-3 text-sm text-emerald-100">{flash.success}</div> : null}
      {flash.error ? <div className="mb-6 rounded-2xl border border-rose-300/20 bg-rose-300/10 px-4 py-3 text-sm text-rose-100">{flash.error}</div> : null}

      <div className="sticky top-4 z-30 mb-6 rounded-[28px] border border-white/10 bg-slate-950/85 px-4 py-4 shadow-[0_20px_60px_rgba(0,0,0,0.35)] backdrop-blur-xl">
        <div className="flex flex-wrap items-center justify-between gap-3">
        <Link href={indexUrl} className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-sm font-semibold text-white transition hover:bg-white/[0.08]">
          <svg aria-hidden="true" viewBox="0 0 16 16" className="h-3.5 w-3.5" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M10.5 3.5 6 8l4.5 4.5" />
          </svg>
          Back to announcements
        </Link>
        <div className="flex flex-wrap gap-3">
          <button type="button" onClick={() => submit('draft')} className="rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-sm font-semibold text-white">Save draft</button>
          <button type="button" onClick={() => submit('published')} className="rounded-full border border-emerald-300/20 bg-emerald-300/10 px-4 py-2 text-sm font-semibold text-emerald-100">Publish</button>
          <button type="button" onClick={() => submit('archived')} className="rounded-full border border-amber-300/20 bg-amber-300/10 px-4 py-2 text-sm font-semibold text-amber-100">Archive</button>
          {destroyUrl ? (
            <button
              type="button"
              onClick={() => {
                if (!window.confirm('Delete this homepage announcement?')) return
                form.delete(destroyUrl, { preserveScroll: true })
              }}
              className="rounded-full border border-rose-300/20 bg-rose-300/10 px-4 py-2 text-sm font-semibold text-rose-100"
            >
              Delete
            </button>
          ) : null}
        </div>
        </div>
      </div>

      <div className="grid items-start gap-6 xl:grid-cols-[minmax(0,1fr)_26rem] 2xl:grid-cols-[minmax(0,1fr)_28rem]">
        <div className="space-y-6">
          <div className="sticky top-[6.75rem] z-20 rounded-[28px] border border-white/10 bg-slate-950/80 p-2 backdrop-blur-xl">
            <div className="flex flex-wrap gap-2">
              {FORM_TABS.map((tab) => (
                <button
                  key={tab.id}
                  type="button"
                  onClick={() => setActiveTab(tab.id)}
                  className={[
                    'rounded-2xl px-4 py-3 text-sm font-semibold transition',
                    activeTab === tab.id
                      ? 'bg-sky-300/14 text-sky-100 ring-1 ring-sky-300/25'
                      : 'text-slate-300 hover:bg-white/[0.04] hover:text-white',
                  ].join(' ')}
                >
                  {tab.label}
                </button>
              ))}
            </div>
            <p className="px-2 pt-3 text-sm text-slate-400">{FORM_TABS.find((tab) => tab.id === activeTab)?.description}</p>
          </div>

          {activeTab === 'overview' ? (
          <>
          <Section title="Basic" description="Core identity, status, and visibility controls.">
            <div className="grid gap-4 md:grid-cols-2">
              <TextField label="Title" value={form.data.title} onChange={(event) => form.setData('title', event.target.value)} error={form.errors.title} maxLength={180} />
              <TextField label="Badge text" value={form.data.badge_text} onChange={(event) => form.setData('badge_text', event.target.value)} error={form.errors.badge_text} maxLength={100} />
            </div>
            <TextField label="Subtitle" value={form.data.subtitle} onChange={(event) => form.setData('subtitle', event.target.value)} error={form.errors.subtitle} maxLength={255} />
            <div className="grid gap-4 md:grid-cols-3">
              <SelectField label="Type" value={form.data.type} onChange={(nextValue) => form.setData('type', nextValue)} options={options.types} error={form.errors.type} />
              <SelectField label="Status" value={form.data.status} onChange={(nextValue) => form.setData('status', nextValue)} options={options.statuses} error={form.errors.status} />
              <TextField label="Priority" value={form.data.priority} onChange={(event) => form.setData('priority', event.target.value)} error={form.errors.priority} inputMode="numeric" />
            </div>
            <ToggleField label="Announcement is active" checked={Boolean(form.data.is_active)} onChange={(event) => form.setData('is_active', event.target.checked)} help="Inactive announcements never surface even when published." />
          </Section>

          <Section title="Schedule" description="Keep launch cards time-bound and predictable.">
            <div className="grid gap-4 md:grid-cols-2">
              <DateTimeField label="Starts at" value={form.data.starts_at} onChange={(nextValue) => form.setData('starts_at', nextValue)} error={form.errors.starts_at} />
              <DateTimeField label="Ends at" value={form.data.ends_at} onChange={(nextValue) => form.setData('ends_at', nextValue)} error={form.errors.ends_at} />
            </div>
          </Section>
          </>
          ) : null}

          {activeTab === 'content' ? (
          <>
          <Section title="Content" description="Only sanitized HTML is stored and rendered on the homepage.">
            <div className="grid gap-3 text-sm text-slate-200">
              <span>Announcement message</span>
              <HomepageAnnouncementEditor
                content={form.data.content_html || ''}
                onChange={(nextValue) => form.setData('content_html', nextValue)}
                placeholder="Write the launch message with headings, lists, links, quotes, and highlighted copy."
                error={form.errors.content_html}
                minHeight={14}
              />
              <div className="rounded-[24px] border border-white/10 bg-black/20 px-4 py-3 text-xs leading-6 text-slate-400">
                Supported formatting matches the homepage sanitizer: paragraphs, bold, italic, links, lists, H2, H3, and blockquotes.
              </div>
            </div>
          </Section>

          <Section title="Links" description="Use entity targets when you know the id, or provide a fallback URL for a stable manual route.">
            <LinkFields title="Primary CTA" prefix="primary" form={form} options={options} />
            <LinkFields title="Secondary CTA" prefix="secondary" form={form} options={options} />
          </Section>
          </>
          ) : null}

          {activeTab === 'design' ? (
          <Section title="Design" description="Choose a launch-ready gradient, optional background image, and glass intensity.">
            <div className="grid gap-4 md:grid-cols-2">
              <SelectField label="Gradient preset" value={form.data.gradient_preset} onChange={(nextValue) => form.setData('gradient_preset', nextValue)} options={options.gradients} error={form.errors.gradient_preset} />
              <SelectField label="Theme preset" value={form.data.theme_preset} onChange={(nextValue) => form.setData('theme_preset', nextValue)} options={options.themes} error={form.errors.theme_preset} />
            </div>
            <div className="grid gap-4 md:grid-cols-2">
              <TextField label="Overlay opacity" value={form.data.overlay_opacity} onChange={(event) => form.setData('overlay_opacity', event.target.value)} error={form.errors.overlay_opacity} inputMode="numeric" />
              <div className="hidden md:block" />
            </div>
            <TextField label="Background image path or URL" value={form.data.background_image} onChange={(event) => form.setData('background_image', event.target.value)} error={form.errors.background_image} placeholder="/storage/homepage-announcements/... or https://..." />
            <BackgroundImageDropzone
              previewUrl={backgroundPreviewUrl}
              storedValue={form.data.background_image}
              selectedFileName={form.data.background_image_file?.name || ''}
              error={backgroundImageError || form.errors.background_image_file}
              onSelect={applyBackgroundFile}
            />
            <ToggleField label="Remove stored background image" checked={Boolean(form.data.remove_background_image)} onChange={(event) => {
              form.setData('remove_background_image', event.target.checked)
              if (event.target.checked) {
                setBackgroundImageError('')
                form.setData('background_image_file', null)
                if (backgroundPreviewUrl?.startsWith?.('blob:')) {
                  URL.revokeObjectURL(backgroundPreviewUrl)
                }
                setBackgroundPreviewUrl('')
              }
            }} help="Turn this on to clear the saved background image on the next save." />
          </Section>
          ) : null}

          {activeTab === 'behavior' ? (
          <Section title="Behavior" description="Dismiss controls let you force a fresh surface when the message materially changes.">
            <div className="grid gap-4 md:grid-cols-2">
              <TextField label="Dismiss version" value={form.data.dismiss_version} onChange={(event) => form.setData('dismiss_version', event.target.value)} error={form.errors.dismiss_version} inputMode="numeric" />
              <SelectField label="Placement" value={form.data.placement} onChange={(nextValue) => form.setData('placement', nextValue)} options={options.placements} error={form.errors.placement} />
            </div>
            <ToggleField label="Users can dismiss this card" checked={Boolean(form.data.is_dismissible)} onChange={(event) => form.setData('is_dismissible', event.target.checked)} help="When disabled, the card remains visible and no restore pill is shown." />
          </Section>
          ) : null}
        </div>

        <aside className="space-y-6 xl:sticky xl:top-[7.5rem] xl:self-start">
          <div>
            <Section title="Preview" description="Refresh the preview to render the sanitized content and resolved CTA payload exactly as the homepage card sees it.">
              <div className="-mx-6 -mt-6 mb-5 border-b border-white/10 bg-slate-950/92 px-6 py-4 backdrop-blur-xl">
                <div className="flex flex-wrap gap-3">
                  <button type="button" onClick={runPreview} disabled={previewBusy} className="rounded-full border border-sky-300/20 bg-sky-300/12 px-4 py-2 text-sm font-semibold text-sky-100 transition hover:bg-sky-300/18 disabled:opacity-60">{previewBusy ? 'Refreshing preview…' : 'Refresh preview'}</button>
                  <button type="button" onClick={() => submit()} className="rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-sm font-semibold text-white transition hover:bg-white/[0.08]">Save changes</button>
                </div>
                {previewError ? <p className="mt-3 text-sm text-rose-300">{previewError}</p> : null}
              </div>
              <div className="overflow-hidden rounded-[30px] border border-white/10 bg-black/20 py-2">
                <HomepageAnnouncement announcement={previewWithLocalImage} mode="preview" />
              </div>
            </Section>
          </div>
        </aside>
      </div>
    </AdminLayout>
  )
}