import React, { useEffect, useMemo, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import { Head, Link, router, useForm } from '@inertiajs/react'
import AdminLayout from '../../../Layouts/AdminLayout'
import RichTextEditor from '../../../components/forum/RichTextEditor'
import WorldMediaUploadField from '../../../components/worlds/editor/WorldMediaUploadField'
import DateTimePicker from '../../../components/ui/DateTimePicker'
import NovaSelect from '../../../components/ui/NovaSelect'

function getField(fields, name) {
  return fields.find((field) => field.name === name) || null
}

const LESSON_SECTION_NAV_ITEMS = [
  { id: 'lesson-story-setup', label: 'Story setup' },
  { id: 'lesson-body-editor', label: 'Main article' },
  { id: 'lesson-ai-comparisons', label: 'AI comparisons' },
  { id: 'lesson-publishing', label: 'Publishing' },
  { id: 'lesson-seo', label: 'SEO' },
  { id: 'lesson-categories', label: 'Categories' },
  { id: 'lesson-cover', label: 'Cover image' },
  { id: 'lesson-preview', label: 'Preview' },
]

let comparisonEditorSequence = 0

function nextComparisonEditorKey(prefix) {
  comparisonEditorSequence += 1
  return `${prefix}-${comparisonEditorSequence}`
}

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

function SectionCard({ id, eyebrow, title, description, actions, children, tone = 'default' }) {
  const toneClass = tone === 'feature'
    ? 'bg-[radial-gradient(circle_at_top_left,rgba(56,189,248,0.16),transparent_38%),linear-gradient(180deg,rgba(15,23,42,0.96),rgba(2,6,23,0.92))] shadow-[0_24px_70px_rgba(2,6,23,0.28)]'
    : 'bg-white/[0.03]'

  return (
    <section id={id} className={`min-w-0 scroll-mt-24 rounded-[28px] border border-white/10 p-5 ${toneClass}`}>
      <div className="flex flex-wrap items-start justify-between gap-4">
        <div className="max-w-3xl">
          {eyebrow ? <p className="text-[11px] font-semibold uppercase tracking-[0.24em] text-sky-200/75">{eyebrow}</p> : null}
          <h2 className="mt-2 text-xl font-semibold tracking-[-0.03em] text-white">{title}</h2>
          {description ? <p className="mt-2 text-sm leading-6 text-slate-400">{description}</p> : null}
        </div>
        {actions ? <div className="flex flex-wrap gap-2">{actions}</div> : null}
      </div>
      <div className="mt-5">{children}</div>
    </section>
  )
}

function SectionNav({ items }) {
  return (
    <div className="sticky top-4 z-20 rounded-[24px] border border-white/10 bg-[linear-gradient(180deg,rgba(7,11,18,0.92),rgba(5,8,14,0.88))] px-3 py-3 shadow-[0_18px_50px_rgba(2,6,23,0.18)] backdrop-blur">
      <div className="flex items-center gap-3 overflow-x-auto pb-1 nova-scrollbar">
        <span className="flex shrink-0 items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-3 py-2 text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400">
          <i className="fa-solid fa-compass text-[10px]" />
          Sections
        </span>
        {items.map((item) => (
          <a
            key={item.id}
            href={`#${item.id}`}
            className="shrink-0 rounded-full border border-white/10 bg-white/[0.03] px-4 py-2 text-sm font-semibold text-white/80 transition hover:border-sky-300/30 hover:bg-sky-300/10 hover:text-white"
          >
            {item.label}
          </a>
        ))}
      </div>
    </div>
  )
}

function TextField({ label, value, onChange, error, hint, ...rest }) {
  return (
    <label className="grid gap-2 text-sm text-slate-300">
      <span className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">{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} />
      {hint ? <span className="text-xs leading-5 text-slate-500">{hint}</span> : null}
      <FieldError message={error} />
    </label>
  )
}

function TextAreaField({ label, value, onChange, error, rows = 4, hint }) {
  return (
    <label className="grid gap-2 text-sm text-slate-300">
      <span className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">{label}</span>
      <textarea value={value ?? ''} onChange={onChange} rows={rows} className="rounded-[24px] border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" />
      {hint ? <span className="text-xs leading-5 text-slate-500">{hint}</span> : null}
      <FieldError message={error} />
    </label>
  )
}

function ToggleField({ label, checked, onChange, help, error }) {
  return (
    <label className="flex items-start gap-3 rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-sm text-slate-200">
      <input type="checkbox" checked={Boolean(checked)} onChange={onChange} className="mt-1" />
      <span>
        <span className="block font-semibold text-white">{label}</span>
        {help ? <span className="mt-1 block text-xs leading-5 text-slate-400">{help}</span> : null}
        <FieldError message={error} />
      </span>
    </label>
  )
}

function slugifyLessonTitle(value) {
  return String(value || '')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')
    .slice(0, 180)
}

function stripHtml(value) {
  return String(value || '')
    .replace(/<style[\s\S]*?<\/style>/gi, ' ')
    .replace(/<script[\s\S]*?<\/script>/gi, ' ')
    .replace(/<[^>]+>/g, ' ')
    .replace(/&nbsp;/g, ' ')
    .replace(/\s+/g, ' ')
    .trim()
}

function countWords(value) {
  const text = stripHtml(value)
  return text ? text.split(/\s+/).length : 0
}

function normalizeCoverPreview(value, cdnBaseUrl) {
  const trimmed = String(value || '').trim()
  if (!trimmed) return ''
  if (trimmed.startsWith('http://') || trimmed.startsWith('https://') || trimmed.startsWith('/')) return trimmed
  return `${String(cdnBaseUrl || '').replace(/\/$/, '')}/${trimmed.replace(/^\//, '')}`
}

function normalizeCategoryValue(value) {
  if (value === '' || value == null) return ''
  return String(value)
}

function normalizeBoolean(value, fallback = false) {
  if (typeof value === 'boolean') return value
  if (typeof value === 'number') return value !== 0
  const normalized = String(value || '').trim().toLowerCase()
  if (['1', 'true', 'yes', 'on'].includes(normalized)) return true
  if (['0', 'false', 'no', 'off'].includes(normalized)) return false
  return fallback
}

const DEFAULT_AI_COMPARISON_TITLE = 'Same Prompt, Different AI Models'

const DEFAULT_AI_COMPARISON_PAYLOAD = {
  title: DEFAULT_AI_COMPARISON_TITLE,
  intro: 'We used the same prompt in multiple image generators to compare composition, mood, detail, and wallpaper quality.',
  prompt: '',
  negative_prompt: '',
  aspect_ratio: '16:9',
  criteria: ['Composition', 'Lighting', 'Wallpaper quality', 'Prompt accuracy', 'Detail quality'],
}

function normalizeCriteria(value) {
  return (Array.isArray(value) ? value : [])
    .map((criterion) => String(criterion || '').trim())
    .filter(Boolean)
}

function normalizeComparisonResult(result, index, cdnBaseUrl) {
  const imagePath = String(result?.image_path || '')
  const thumbPath = String(result?.thumb_path || '')

  return {
    client_key: result?.client_key || nextComparisonEditorKey('comparison-result'),
    id: result?.id ?? null,
    provider: String(result?.provider || ''),
    model_name: String(result?.model_name || ''),
    image_path: imagePath,
    image_url: String(result?.image_url || normalizeCoverPreview(imagePath, cdnBaseUrl) || ''),
    image_temp_path: String(result?.image_temp_path || ''),
    thumb_path: thumbPath,
    thumb_url: String(result?.thumb_url || normalizeCoverPreview(thumbPath, cdnBaseUrl) || ''),
    thumb_temp_path: String(result?.thumb_temp_path || ''),
    settings: String(result?.settings || ''),
    strengths: String(result?.strengths || ''),
    weaknesses: String(result?.weaknesses || ''),
    best_for: String(result?.best_for || ''),
    score: result?.score == null || result?.score === '' ? '' : Number(result.score),
    sort_order: Number(result?.sort_order ?? index),
    active: normalizeBoolean(result?.active, true),
  }
}

function createEmptyComparisonResult(sortOrder = 0) {
  return normalizeComparisonResult({ sort_order: sortOrder, active: true }, sortOrder, '')
}

function normalizeComparisonBlock(block, index, cdnBaseUrl) {
  const payload = block?.payload && typeof block.payload === 'object' ? block.payload : {}

  return {
    client_key: block?.client_key || nextComparisonEditorKey('comparison-block'),
    id: block?.id ?? null,
    type: 'ai_comparison',
    title: String(block?.title || payload?.title || DEFAULT_AI_COMPARISON_TITLE),
    payload: {
      ...DEFAULT_AI_COMPARISON_PAYLOAD,
      title: String(payload?.title || block?.title || DEFAULT_AI_COMPARISON_TITLE),
      intro: String(payload?.intro || ''),
      prompt: String(payload?.prompt || ''),
      negative_prompt: String(payload?.negative_prompt || ''),
      aspect_ratio: String(payload?.aspect_ratio || DEFAULT_AI_COMPARISON_PAYLOAD.aspect_ratio),
      criteria: normalizeCriteria(payload?.criteria || DEFAULT_AI_COMPARISON_PAYLOAD.criteria),
    },
    sort_order: Number(block?.sort_order ?? index),
    active: normalizeBoolean(block?.active, true),
    comparison_results: (Array.isArray(block?.comparison_results) ? block.comparison_results : [])
      .map((result, resultIndex) => normalizeComparisonResult(result, resultIndex, cdnBaseUrl)),
  }
}

function createEmptyComparisonBlock(sortOrder = 0, cdnBaseUrl = '') {
  return normalizeComparisonBlock({
    type: 'ai_comparison',
    title: DEFAULT_AI_COMPARISON_TITLE,
    payload: DEFAULT_AI_COMPARISON_PAYLOAD,
    sort_order: sortOrder,
    active: true,
    comparison_results: [],
  }, sortOrder, cdnBaseUrl)
}

function normalizeComparisonBlocks(blocks, cdnBaseUrl) {
  return (Array.isArray(blocks) ? blocks : [])
    .filter((block) => String(block?.type || 'ai_comparison') === 'ai_comparison')
    .map((block, index) => normalizeComparisonBlock(block, index, cdnBaseUrl))
}

function serializeComparisonBlocks(blocks) {
  return (Array.isArray(blocks) ? blocks : []).map((block, index) => ({
    id: block.id || undefined,
    type: 'ai_comparison',
    title: String(block.title || block.payload?.title || DEFAULT_AI_COMPARISON_TITLE),
    payload: {
      title: String(block.payload?.title || block.title || DEFAULT_AI_COMPARISON_TITLE),
      intro: String(block.payload?.intro || ''),
      prompt: String(block.payload?.prompt || ''),
      negative_prompt: String(block.payload?.negative_prompt || ''),
      aspect_ratio: String(block.payload?.aspect_ratio || ''),
      criteria: normalizeCriteria(block.payload?.criteria || []),
    },
    sort_order: Number(block.sort_order ?? index),
    active: Boolean(block.active),
    comparison_results: (Array.isArray(block.comparison_results) ? block.comparison_results : []).map((result, resultIndex) => ({
      id: result.id || undefined,
      provider: String(result.provider || ''),
      model_name: String(result.model_name || ''),
      image_path: String(result.image_path || ''),
      thumb_path: String(result.thumb_path || ''),
      settings: String(result.settings || ''),
      strengths: String(result.strengths || ''),
      weaknesses: String(result.weaknesses || ''),
      best_for: String(result.best_for || ''),
      score: result.score === '' || result.score == null ? null : Number(result.score),
      sort_order: Number(result.sort_order ?? resultIndex),
      active: Boolean(result.active),
    })),
  }))
}

function getFormError(errors, path) {
  return errors?.[path] || ''
}

function buildLessonPayload(data) {
  return {
    category_id: data.category_id === '' || data.category_id == null ? null : Number(data.category_id),
    title: String(data.title || ''),
    slug: String(data.slug || ''),
    excerpt: String(data.excerpt || ''),
    content: String(data.content || ''),
    difficulty: String(data.difficulty || ''),
    access_level: String(data.access_level || ''),
    lesson_type: String(data.lesson_type || ''),
    cover_image: String(data.cover_image || ''),
    video_url: String(data.video_url || ''),
    reading_minutes: data.reading_minutes === '' || data.reading_minutes == null ? '' : Number(data.reading_minutes),
    published_at: data.published_at || '',
    seo_title: String(data.seo_title || ''),
    seo_description: String(data.seo_description || ''),
    featured: Boolean(data.featured),
    active: Boolean(data.active),
    blocks: serializeComparisonBlocks(data.blocks),
  }
}

function parseLessonImport(rawText, categoryOptions) {
  let parsed

  try {
    parsed = JSON.parse(String(rawText || ''))
  } catch {
    throw new Error('Could not parse JSON.')
  }

  if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {
    throw new Error('Import JSON must be an object.')
  }

  const next = {}
  const applied = []

  const apply = (key, value) => {
    next[key] = value
    applied.push(key)
  }

  if (parsed.title != null) apply('title', String(parsed.title))
  if (parsed.slug != null) apply('slug', String(parsed.slug))
  if (parsed.excerpt != null) apply('excerpt', String(parsed.excerpt))
  if (parsed.content != null) apply('content', String(parsed.content))
  if (parsed.body != null && parsed.content == null) apply('content', String(parsed.body))
  if (parsed.html != null && parsed.content == null && parsed.body == null) apply('content', String(parsed.html))
  if (parsed.difficulty != null) apply('difficulty', String(parsed.difficulty))
  if (parsed.access_level != null) apply('access_level', String(parsed.access_level))
  if (parsed.access != null && parsed.access_level == null) apply('access_level', String(parsed.access))
  if (parsed.lesson_type != null) apply('lesson_type', String(parsed.lesson_type))
  if (parsed.type != null && parsed.lesson_type == null) apply('lesson_type', String(parsed.type))
  if (parsed.cover_image != null) apply('cover_image', String(parsed.cover_image))
  if (parsed.cover != null && parsed.cover_image == null) apply('cover_image', String(parsed.cover))
  if (parsed.cover_url != null && parsed.cover_image == null && parsed.cover == null) apply('cover_image', String(parsed.cover_url))
  if (parsed.video_url != null) apply('video_url', String(parsed.video_url))
  if (parsed.reading_minutes != null) apply('reading_minutes', String(parsed.reading_minutes))
  if (parsed.published_at != null) apply('published_at', String(parsed.published_at))
  if (parsed.seo_title != null) apply('seo_title', String(parsed.seo_title))
  if (parsed.seo_description != null) apply('seo_description', String(parsed.seo_description))
  if (parsed.featured != null) apply('featured', normalizeBoolean(parsed.featured))
  if (parsed.active != null) apply('active', normalizeBoolean(parsed.active, true))

  if (parsed.category_id != null || parsed.category_slug != null || parsed.category != null) {
    const requested = String(parsed.category_id ?? parsed.category_slug ?? parsed.category).trim().toLowerCase()
    const match = (Array.isArray(categoryOptions) ? categoryOptions : []).find((option) => [option.id, option.value, option.slug, option.name, option.label]
      .filter((candidate) => candidate != null)
      .map((candidate) => String(candidate).trim().toLowerCase())
      .includes(requested))

    if (match) {
      apply('category_id', String(match.id ?? match.value ?? ''))
    }
  }

  if (applied.length === 0) {
    throw new Error('The JSON did not contain any recognized lesson fields.')
  }

  return { next, applied }
}

function JsonImportDialog({ open, value, error, onChange, onClose, onApply }) {
  const backdropRef = useRef(null)

  useEffect(() => {
    if (!open) return undefined

    const handleKeyDown = (event) => {
      if (event.key === 'Escape') {
        onClose?.()
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
  }, [onClose, open])

  if (!open) return null

  return createPortal(
    <div
      ref={backdropRef}
      className="fixed inset-0 z-[9999] flex items-center justify-center bg-[#04070dcc] px-4 backdrop-blur-md"
      onClick={(event) => {
        if (event.target === backdropRef.current) {
          onClose?.()
        }
      }}
      role="presentation"
    >
      <div className="w-full max-w-3xl overflow-hidden rounded-3xl border border-white/10 bg-[linear-gradient(180deg,rgba(16,22,34,0.98),rgba(8,12,19,0.98))] shadow-[0_30px_80px_rgba(0,0,0,0.55)]">
        <div className="border-b border-white/[0.06] bg-white/[0.02] px-6 py-5">
          <p className="text-[11px] font-semibold uppercase tracking-[0.24em] text-white/35">Structured Import</p>
          <h3 className="mt-2 text-lg font-semibold text-white">Paste lesson JSON</h3>
          <p className="mt-2 text-sm leading-6 text-white/65">Use this to seed the lesson form with structured content before you refine it in the editor.</p>
        </div>

        <div className="grid gap-5 px-6 py-5 xl:grid-cols-[minmax(0,1fr)_280px]">
          <div className="grid gap-3">
            <textarea
              value={value}
              onChange={(event) => onChange?.(event.target.value)}
              rows={16}
              placeholder={'{\n  "title": "Prompt engineering for cleaner scene direction",\n  "excerpt": "Short summary...",\n  "content": "<p>Rich HTML body...</p>",\n  "category": "Prompting",\n  "difficulty": "beginner"\n}'}
              className="rounded-[24px] border border-white/10 bg-slate-950/80 px-4 py-4 font-mono text-sm leading-6 text-slate-100 outline-none"
            />
            {error ? <div className="rounded-2xl border border-rose-300/20 bg-rose-400/10 px-4 py-3 text-sm text-rose-100">{error}</div> : null}
          </div>

          <div className="rounded-[24px] border border-white/10 bg-white/[0.03] p-4 text-sm text-slate-300">
            <div className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">Accepted keys</div>
            <div className="mt-3 space-y-2 leading-6 text-slate-400">
              <p>title, slug, excerpt</p>
              <p>content, body, html</p>
              <p>category_id, category_slug, category</p>
              <p>difficulty, access_level, lesson_type</p>
              <p>cover_image, cover, cover_url, video_url</p>
              <p>reading_minutes, published_at</p>
              <p>seo_title, seo_description, featured, active</p>
            </div>
          </div>
        </div>

        <div className="flex items-center justify-end gap-3 border-t border-white/[0.06] px-6 py-4">
          <button type="button" onClick={() => onClose?.()} className="inline-flex items-center justify-center rounded-full border border-white/[0.08] bg-white/[0.04] px-4 py-2 text-sm font-medium text-white/70 transition hover:bg-white/[0.08] hover:text-white">Cancel</button>
          <button type="button" onClick={() => onApply?.()} className="inline-flex items-center justify-center rounded-full border border-sky-300/25 bg-sky-400/90 px-4 py-2 text-sm font-semibold text-slate-950 transition hover:brightness-110">Apply JSON</button>
        </div>
      </div>
    </div>,
    document.body,
  )
}

export default function LessonEditor({ title, subtitle, fields, record, submitUrl, indexUrl, destroyUrl, method, editorContext = {} }) {
  const cdnBaseUrl = editorContext.coverCdnBaseUrl || ''
  const form = useForm({
    ...record,
    category_id: normalizeCategoryValue(record.category_id),
    blocks: normalizeComparisonBlocks(record.blocks, cdnBaseUrl),
  })
  const [coverPreviewUrl, setCoverPreviewUrl] = useState(record.cover_image_url || normalizeCoverPreview(record.cover_image, editorContext.coverCdnBaseUrl))
  const [stagedCoverPath, setStagedCoverPath] = useState('')
  const [categories, setCategories] = useState(Array.isArray(editorContext.categories) ? editorContext.categories : [])
  const [jsonImportOpen, setJsonImportOpen] = useState(false)
  const [jsonImportValue, setJsonImportValue] = useState('')
  const [jsonImportError, setJsonImportError] = useState('')
  const [categoryError, setCategoryError] = useState('')
  const [categorySaving, setCategorySaving] = useState(false)
  const [categoryDraft, setCategoryDraft] = useState({ type: 'lesson', name: '', slug: '', description: '', order_num: 0, active: true })
  const slugTouchedRef = useRef(Boolean(String(record.slug || '').trim()))
  const difficultyField = useMemo(() => getField(fields, 'difficulty'), [fields])
  const accessField = useMemo(() => getField(fields, 'access_level'), [fields])
  const bodyWordCount = useMemo(() => countWords(form.data.content), [form.data.content])
  const excerptLength = String(form.data.excerpt || '').length
  const csrfToken = useMemo(() => {
    if (typeof document === 'undefined') return ''
    return document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''
  }, [])

  useEffect(() => {
    if (slugTouchedRef.current) return
    form.setData('slug', slugifyLessonTitle(form.data.title))
  }, [form.data.title])

  const categoryOptions = useMemo(() => {
    const next = categories.map((category) => ({ value: String(category.id), label: category.name }))
    return [{ value: '', label: 'No category' }, ...next]
  }, [categories])

  const handleManualCoverChange = (nextValue) => {
    form.setData('cover_image', nextValue)
    setCoverPreviewUrl(normalizeCoverPreview(nextValue, editorContext.coverCdnBaseUrl))
  }

  const updateBlocks = (updater) => {
    const currentBlocks = Array.isArray(form.data.blocks) ? form.data.blocks : []
    const nextBlocks = typeof updater === 'function' ? updater(currentBlocks) : updater
    form.setData('blocks', nextBlocks)
  }

  const updateBlock = (blockKey, updater) => {
    updateBlocks((currentBlocks) => currentBlocks.map((block) => (
      block.client_key === blockKey ? updater(block) : block
    )))
  }

  const removeBlock = (blockKey) => {
    updateBlocks((currentBlocks) => currentBlocks.filter((block) => block.client_key !== blockKey))
  }

  const addComparisonBlock = () => {
    updateBlocks((currentBlocks) => ([
      ...currentBlocks,
      createEmptyComparisonBlock(currentBlocks.length, cdnBaseUrl),
    ]))
  }

  const addComparisonResult = (blockKey) => {
    updateBlock(blockKey, (block) => ({
      ...block,
      comparison_results: [
        ...(Array.isArray(block.comparison_results) ? block.comparison_results : []),
        createEmptyComparisonResult(Array.isArray(block.comparison_results) ? block.comparison_results.length : 0),
      ],
    }))
  }

  const updateComparisonResult = (blockKey, resultKey, updater) => {
    updateBlock(blockKey, (block) => ({
      ...block,
      comparison_results: (Array.isArray(block.comparison_results) ? block.comparison_results : []).map((result) => (
        result.client_key === resultKey ? updater(result) : result
      )),
    }))
  }

  const removeComparisonResult = (blockKey, resultKey) => {
    updateBlock(blockKey, (block) => ({
      ...block,
      comparison_results: (Array.isArray(block.comparison_results) ? block.comparison_results : []).filter((result) => result.client_key !== resultKey),
    }))
  }

  const submit = (event) => {
    event.preventDefault()
    const payload = buildLessonPayload(form.data)
    form.transform(() => payload)

    if (method === 'patch') {
      form.patch(submitUrl)
      return
    }

    form.post(submitUrl)
  }

  const deleteLesson = () => {
    if (!destroyUrl) return
    if (!window.confirm('Delete this lesson?')) return
    router.delete(destroyUrl)
  }

  const applyJsonImport = () => {
    try {
      const parsed = parseLessonImport(jsonImportValue, categories)

      Object.entries(parsed.next).forEach(([key, value]) => {
        form.setData(key, value)
      })

      if (parsed.next.cover_image != null) {
        handleManualCoverChange(String(parsed.next.cover_image || ''))
      }

      if (parsed.next.slug != null) {
        slugTouchedRef.current = true
      }

      setJsonImportError('')
      setJsonImportOpen(false)
    } catch (error) {
      setJsonImportError(error instanceof Error ? error.message : 'Could not parse JSON.')
    }
  }

  const createCategory = async () => {
    setCategorySaving(true)
    setCategoryError('')

    try {
      const response = await fetch(editorContext.categoryStoreUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRF-TOKEN': csrfToken,
          Accept: 'application/json',
        },
        credentials: 'same-origin',
        body: JSON.stringify({
          ...categoryDraft,
          order_num: Number(categoryDraft.order_num || 0),
          slug: categoryDraft.slug || slugifyLessonTitle(categoryDraft.name),
        }),
      })

      const payload = await response.json().catch(() => ({}))
      if (!response.ok) {
        const firstError = payload?.errors ? Object.values(payload.errors)[0]?.[0] : null
        throw new Error(firstError || payload?.message || 'Could not create category.')
      }

      const nextCategory = payload?.category
      if (!nextCategory?.id) {
        throw new Error('Category response was incomplete.')
      }

      setCategories((current) => [...current, nextCategory].sort((left, right) => {
        if (left.order_num !== right.order_num) return Number(left.order_num || 0) - Number(right.order_num || 0)
        return String(left.name || '').localeCompare(String(right.name || ''))
      }))
      form.setData('category_id', String(nextCategory.id))
      setCategoryDraft({ type: 'lesson', name: '', slug: '', description: '', order_num: 0, active: true })
    } catch (error) {
      setCategoryError(error instanceof Error ? error.message : 'Could not create category.')
    } finally {
      setCategorySaving(false)
    }
  }

  const comparisonBlocks = Array.isArray(form.data.blocks) ? form.data.blocks : []

  return (
    <AdminLayout title={title} subtitle={subtitle}>
      <Head title={`Admin · ${title}`} />

      <form onSubmit={submit} className="space-y-6 pb-16">
        <section className="overflow-hidden rounded-[28px] border border-white/10 bg-[radial-gradient(circle_at_top_left,rgba(56,189,248,0.14),transparent_34%),linear-gradient(180deg,rgba(15,23,42,0.96),rgba(2,6,23,0.94))] shadow-[0_24px_70px_rgba(2,6,23,0.34)] backdrop-blur">
          <div className="flex flex-wrap items-start justify-between gap-4 border-b border-white/10 px-5 py-4">
            <div className="min-w-0 flex-1">
              <div className="flex flex-wrap items-center gap-2 text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">
                <Link href={indexUrl} className="rounded-full border border-white/10 bg-white/[0.04] px-3 py-1.5 text-white transition hover:bg-white/[0.08]">Back to lessons</Link>
                <span>{destroyUrl ? 'Edit lesson' : 'New lesson'}</span>
              </div>
              <h1 className="mt-3 text-3xl font-semibold tracking-[-0.05em] text-white">{form.data.title || 'Untitled academy lesson'}</h1>
              <p className="mt-2 max-w-3xl text-sm leading-7 text-slate-300">Use the same richer writing flow as the newsroom: drag in the cover, shape the article with the rich editor, and keep publishing details in the same place.</p>
            </div>
            <div className="flex flex-wrap gap-3">
              <button type="button" onClick={() => setJsonImportOpen(true)} className="rounded-2xl border border-white/10 bg-white/[0.05] px-4 py-2.5 text-sm font-semibold text-white transition hover:bg-white/[0.08]">Import JSON</button>
              <button type="submit" disabled={form.processing} className="rounded-2xl border border-sky-300/25 bg-sky-300/12 px-4 py-2.5 text-sm font-semibold text-sky-100">{form.processing ? 'Saving...' : 'Save lesson'}</button>
            </div>
          </div>
        </section>

        <SectionNav items={LESSON_SECTION_NAV_ITEMS} />

        <div className="grid gap-6 xl:grid-cols-[minmax(0,1fr)_360px] xl:items-start">
          <div className="min-w-0 space-y-6">
            <SectionCard id="lesson-story-setup" eyebrow="Story setup" title="Headline and framing" description="Start with the lesson identity and summary, then move into the full article body." tone="feature">
              <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}
                  placeholder="Prompt engineering for cleaner scene direction"
                />
                <label className="grid gap-2 text-sm text-slate-300">
                  <span className="flex items-center justify-between gap-3 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">
                    <span>Slug</span>
                    <button type="button" onClick={() => {
                      slugTouchedRef.current = false
                      form.setData('slug', slugifyLessonTitle(form.data.title))
                    }} className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1 text-[10px] font-semibold text-white">Sync</button>
                  </span>
                  <input
                    value={form.data.slug}
                    onChange={(event) => {
                      slugTouchedRef.current = String(event.target.value).trim() !== ''
                      form.setData('slug', event.target.value)
                    }}
                    className="rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-white outline-none"
                    placeholder="prompt-engineering-for-cleaner-scene-direction"
                    maxLength={180}
                  />
                  <span className="text-xs leading-5 text-slate-500">The slug follows the title until you override it manually.</span>
                  <FieldError message={form.errors.slug} />
                </label>
              </div>

              <label className="grid gap-2 text-sm text-slate-300">
                <span className="flex items-center justify-between gap-3 text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">
                  <span>Excerpt</span>
                  <span>{excerptLength}/800</span>
                </span>
                <textarea value={form.data.excerpt} onChange={(event) => form.setData('excerpt', event.target.value)} rows={5} className="rounded-[24px] border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" placeholder="Summarize what the lesson teaches, why it matters, and what a creator will walk away with." />
                <span className="text-xs leading-5 text-slate-500">This is the short summary used in cards, internal lists, and metadata surfaces.</span>
                <FieldError message={form.errors.excerpt} />
              </label>
            </SectionCard>

            <SectionCard id="lesson-body-editor" eyebrow="Main article" title="Lesson body editor" description="Write the tutorial in the same richer editing surface used for newsroom articles." actions={<div className="rounded-full border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs font-semibold uppercase tracking-[0.14em] text-white">{bodyWordCount.toLocaleString()} words</div>}>
              <div className="grid min-w-0 gap-3 text-sm text-slate-300">
                <RichTextEditor
                  content={form.data.content}
                  onChange={(nextValue) => form.setData('content', nextValue)}
                  placeholder="Open with the problem, explain the workflow step by step, and use headings, media, and links where the lesson needs structure."
                  error={form.errors.content}
                  minHeight={24}
                  autofocus={false}
                  advancedNews
                  mediaSupport={{
                    uploadUrl: editorContext.bodyMediaUploadUrl,
                    deleteUrl: editorContext.bodyMediaDeleteUrl,
                    assetsUrl: editorContext.bodyMediaAssetsUrl,
                    slot: 'body',
                  }}
                />
                <div className="rounded-[24px] border border-white/10 bg-black/20 px-4 py-3 text-xs leading-6 text-slate-400">
                  Tutorial workflow suggestion: define the outcome, break the process into clear steps, call out traps or quality checks, then finish with a practical next move.
                </div>
              </div>
            </SectionCard>

            <SectionCard
              id="lesson-ai-comparisons"
              eyebrow="Structured blocks"
              title="AI model comparisons"
              description="Add reusable same-prompt comparison blocks without burying the data inside the lesson HTML body."
              actions={<button type="button" onClick={addComparisonBlock} className="rounded-full border border-[#ff9e8c]/25 bg-[#ff9e8c]/12 px-4 py-2 text-sm font-semibold text-[#ffd5cd]">+ Add AI Comparison</button>}
            >
              <div className="space-y-5">
                {comparisonBlocks.length === 0 ? (
                  <div className="rounded-[24px] border border-dashed border-white/10 bg-black/20 px-5 py-6 text-sm leading-7 text-slate-400">
                    No comparison blocks yet. Add one when a lesson needs the same prompt analyzed across multiple AI image tools.
                  </div>
                ) : comparisonBlocks.map((block, blockIndex) => (
                  <div key={block.client_key} className="rounded-[28px] border border-white/10 bg-[radial-gradient(circle_at_top_left,rgba(255,158,140,0.12),transparent_34%),linear-gradient(180deg,rgba(15,23,42,0.82),rgba(6,10,18,0.95))] p-5 shadow-[0_24px_60px_rgba(2,6,23,0.22)]">
                    <div className="flex flex-wrap items-start justify-between gap-3 border-b border-white/10 pb-4">
                      <div>
                        <p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-[#ffc0b4]">AI Model Comparison</p>
                        <h3 className="mt-2 text-xl font-semibold tracking-[-0.03em] text-white">{block.payload?.title || block.title || DEFAULT_AI_COMPARISON_TITLE}</h3>
                      </div>
                      <div className="flex flex-wrap gap-2">
                        <button type="button" onClick={() => removeBlock(block.client_key)} className="rounded-full border border-rose-300/20 bg-rose-300/10 px-3 py-1.5 text-xs font-semibold text-rose-100">Remove block</button>
                      </div>
                    </div>

                    <div className="mt-5 grid gap-4 lg:grid-cols-2">
                      <TextField
                        label="Block title"
                        value={block.title}
                        onChange={(event) => updateBlock(block.client_key, (current) => ({
                          ...current,
                          title: event.target.value,
                          payload: { ...current.payload, title: event.target.value },
                        }))}
                        error={getFormError(form.errors, `blocks.${blockIndex}.title`) || getFormError(form.errors, `blocks.${blockIndex}.payload.title`)}
                        placeholder={DEFAULT_AI_COMPARISON_TITLE}
                      />
                      <TextField
                        label="Aspect ratio"
                        value={block.payload?.aspect_ratio}
                        onChange={(event) => updateBlock(block.client_key, (current) => ({ ...current, payload: { ...current.payload, aspect_ratio: event.target.value } }))}
                        error={getFormError(form.errors, `blocks.${blockIndex}.payload.aspect_ratio`)}
                        placeholder="16:9"
                      />
                    </div>

                    <div className="mt-4 grid gap-4">
                      <TextAreaField
                        label="Intro"
                        value={block.payload?.intro}
                        onChange={(event) => updateBlock(block.client_key, (current) => ({ ...current, payload: { ...current.payload, intro: event.target.value } }))}
                        error={getFormError(form.errors, `blocks.${blockIndex}.payload.intro`)}
                        rows={3}
                      />
                      <TextAreaField
                        label="Prompt"
                        value={block.payload?.prompt}
                        onChange={(event) => updateBlock(block.client_key, (current) => ({ ...current, payload: { ...current.payload, prompt: event.target.value } }))}
                        error={getFormError(form.errors, `blocks.${blockIndex}.payload.prompt`)}
                        rows={5}
                      />
                      <TextAreaField
                        label="Negative prompt"
                        value={block.payload?.negative_prompt}
                        onChange={(event) => updateBlock(block.client_key, (current) => ({ ...current, payload: { ...current.payload, negative_prompt: event.target.value } }))}
                        error={getFormError(form.errors, `blocks.${blockIndex}.payload.negative_prompt`)}
                        rows={3}
                      />
                    </div>

                    <div className="mt-4 grid gap-4 lg:grid-cols-[minmax(0,1fr)_200px_200px]">
                      <TextAreaField
                        label="Criteria (one per line)"
                        value={(block.payload?.criteria || []).join('\n')}
                        onChange={(event) => updateBlock(block.client_key, (current) => ({
                          ...current,
                          payload: { ...current.payload, criteria: normalizeCriteria(String(event.target.value || '').split(/\r?\n/)) },
                        }))}
                        error={getFormError(form.errors, `blocks.${blockIndex}.payload.criteria`) || getFormError(form.errors, `blocks.${blockIndex}.payload.criteria.0`)}
                        rows={6}
                        hint="Composition, lighting, wallpaper quality, and similar criteria work well here."
                      />
                      <TextField
                        label="Sort order"
                        value={block.sort_order}
                        onChange={(event) => updateBlock(block.client_key, (current) => ({ ...current, sort_order: event.target.value }))}
                        error={getFormError(form.errors, `blocks.${blockIndex}.sort_order`)}
                        type="number"
                        min="0"
                      />
                      <ToggleField
                        label="Active"
                        checked={Boolean(block.active)}
                        onChange={(event) => updateBlock(block.client_key, (current) => ({ ...current, active: event.target.checked }))}
                        error={getFormError(form.errors, `blocks.${blockIndex}.active`)}
                        help="Inactive comparison blocks stay stored but are hidden on the public lesson page."
                      />
                    </div>

                    <div className="mt-6 rounded-[24px] border border-white/10 bg-black/20 p-4">
                      <div className="flex flex-wrap items-center justify-between gap-3">
                        <div>
                          <p className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">Results</p>
                          <p className="mt-1 text-sm text-slate-400">Add one card per tool or model you want to compare.</p>
                        </div>
                        <button type="button" onClick={() => addComparisonResult(block.client_key)} className="rounded-full border border-sky-300/25 bg-sky-300/12 px-4 py-2 text-sm font-semibold text-sky-100">+ Add model result</button>
                      </div>

                      <div className="mt-4 space-y-4">
                        {(block.comparison_results || []).length === 0 ? (
                          <div className="rounded-[22px] border border-dashed border-white/10 bg-white/[0.03] px-4 py-5 text-sm text-slate-500">No model results yet.</div>
                        ) : (block.comparison_results || []).map((result, resultIndex) => (
                          <div key={result.client_key} className="rounded-[24px] border border-white/10 bg-slate-950/70 p-4">
                            <div className="flex flex-wrap items-start justify-between gap-3">
                              <div>
                                <div className="text-sm font-semibold text-white">{result.model_name || result.provider || `Model result ${resultIndex + 1}`}</div>
                                <div className="mt-1 text-xs uppercase tracking-[0.16em] text-slate-500">Comparison card</div>
                              </div>
                              <button type="button" onClick={() => removeComparisonResult(block.client_key, result.client_key)} className="rounded-full border border-rose-300/20 bg-rose-300/10 px-3 py-1.5 text-xs font-semibold text-rose-100">Remove</button>
                            </div>

                            <div className="mt-4 grid gap-4 xl:grid-cols-2">
                              <WorldMediaUploadField
                                label="Generated image"
                                slot="body"
                                value={result.image_path}
                                previewUrl={result.image_url}
                                emptyLabel="Generated image"
                                helperText="Upload the main comparison image using the same Academy lesson media pipeline."
                                uploadUrl={editorContext.bodyMediaUploadUrl}
                                deleteUrl={editorContext.bodyMediaDeleteUrl}
                                isTemporaryValue={Boolean(result.image_temp_path) && result.image_temp_path === result.image_path}
                                onChange={({ path, url }) => updateComparisonResult(block.client_key, result.client_key, (current) => ({
                                  ...current,
                                  image_path: path || '',
                                  image_url: url || normalizeCoverPreview(path || '', cdnBaseUrl),
                                  image_temp_path: path || '',
                                }))}
                              />
                              <WorldMediaUploadField
                                label="Thumbnail image"
                                slot="body"
                                value={result.thumb_path}
                                previewUrl={result.thumb_url}
                                emptyLabel="Thumbnail"
                                helperText="Optional smaller variant. Leave empty to reuse the main image on the public lesson page."
                                uploadUrl={editorContext.bodyMediaUploadUrl}
                                deleteUrl={editorContext.bodyMediaDeleteUrl}
                                isTemporaryValue={Boolean(result.thumb_temp_path) && result.thumb_temp_path === result.thumb_path}
                                onChange={({ path, url }) => updateComparisonResult(block.client_key, result.client_key, (current) => ({
                                  ...current,
                                  thumb_path: path || '',
                                  thumb_url: url || normalizeCoverPreview(path || '', cdnBaseUrl),
                                  thumb_temp_path: path || '',
                                }))}
                              />
                            </div>

                            <div className="mt-4 grid gap-4 lg:grid-cols-2 xl:grid-cols-4">
                              <TextField
                                label="Provider"
                                value={result.provider}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({ ...current, provider: event.target.value }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.provider`)}
                                placeholder="OpenAI"
                              />
                              <TextField
                                label="Model"
                                value={result.model_name}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({ ...current, model_name: event.target.value }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.model_name`)}
                                placeholder="ChatGPT Images"
                              />
                              <TextField
                                label="Score"
                                value={result.score}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({ ...current, score: event.target.value }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.score`)}
                                type="number"
                                min="1"
                                max="10"
                              />
                              <TextField
                                label="Sort order"
                                value={result.sort_order}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({ ...current, sort_order: event.target.value }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.sort_order`)}
                                type="number"
                                min="0"
                              />
                            </div>

                            <div className="mt-4 grid gap-4 lg:grid-cols-2">
                              <TextAreaField
                                label="Settings"
                                value={result.settings}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({ ...current, settings: event.target.value }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.settings`)}
                                rows={3}
                              />
                              <TextAreaField
                                label="Strengths"
                                value={result.strengths}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({ ...current, strengths: event.target.value }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.strengths`)}
                                rows={3}
                              />
                              <TextAreaField
                                label="Weaknesses"
                                value={result.weaknesses}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({ ...current, weaknesses: event.target.value }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.weaknesses`)}
                                rows={3}
                              />
                              <TextAreaField
                                label="Best for"
                                value={result.best_for}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({ ...current, best_for: event.target.value }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.best_for`)}
                                rows={3}
                              />
                            </div>

                            <div className="mt-4 grid gap-4 lg:grid-cols-2">
                              <TextField
                                label="Image path override"
                                value={result.image_path}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({
                                  ...current,
                                  image_path: event.target.value,
                                  image_url: normalizeCoverPreview(event.target.value, cdnBaseUrl),
                                  image_temp_path: '',
                                }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.image_path`)}
                                placeholder="academy/lessons/body/..."
                              />
                              <TextField
                                label="Thumbnail path override"
                                value={result.thumb_path}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({
                                  ...current,
                                  thumb_path: event.target.value,
                                  thumb_url: normalizeCoverPreview(event.target.value, cdnBaseUrl),
                                  thumb_temp_path: '',
                                }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.thumb_path`)}
                                placeholder="Optional academy/lessons/body/..."
                              />
                            </div>

                            <div className="mt-4">
                              <ToggleField
                                label="Result active"
                                checked={Boolean(result.active)}
                                onChange={(event) => updateComparisonResult(block.client_key, result.client_key, (current) => ({ ...current, active: event.target.checked }))}
                                error={getFormError(form.errors, `blocks.${blockIndex}.comparison_results.${resultIndex}.active`)}
                                help="Inactive results stay saved but do not render on the public lesson page."
                              />
                            </div>
                          </div>
                        ))}
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            </SectionCard>

            <SectionCard id="lesson-publishing" eyebrow="Publishing" title="Placement and visibility" description="Set the lesson metadata, schedule, and discovery fields before it goes live.">
              <div className="grid gap-4 md:grid-cols-2">
                <div className="grid gap-2 text-sm text-slate-300">
                  <NovaSelect label="Difficulty" value={form.data.difficulty || ''} onChange={(nextValue) => form.setData('difficulty', String(nextValue || ''))} options={difficultyField?.options || []} searchable={false} className="bg-black/20" error={form.errors.difficulty} />
                </div>
                <div className="grid gap-2 text-sm text-slate-300">
                  <NovaSelect label="Access" value={form.data.access_level || ''} onChange={(nextValue) => form.setData('access_level', String(nextValue || ''))} options={accessField?.options || []} searchable={false} className="bg-black/20" error={form.errors.access_level} />
                </div>
              </div>

              <div className="grid gap-4 md:grid-cols-2">
                <TextField label="Lesson type" value={form.data.lesson_type} onChange={(event) => form.setData('lesson_type', event.target.value)} error={form.errors.lesson_type} placeholder="article, video, walkthrough" />
                <TextField label="Reading minutes" value={form.data.reading_minutes} onChange={(event) => form.setData('reading_minutes', event.target.value)} error={form.errors.reading_minutes} type="number" min="1" max="999" />
              </div>

              <div className="grid gap-4 md:grid-cols-2">
                <div className="grid gap-2 text-sm text-slate-300">
                  <NovaSelect label="Category" value={form.data.category_id || ''} onChange={(nextValue) => form.setData('category_id', String(nextValue || ''))} options={categoryOptions} searchable={false} className="bg-black/20" error={form.errors.category_id} />
                </div>
                <div className="grid gap-2 text-sm text-slate-300">
                  <span className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">Publish at</span>
                  <DateTimePicker value={form.data.published_at || ''} onChange={(nextValue) => form.setData('published_at', nextValue || '')} clearable className="bg-black/20" />
                  <FieldError message={form.errors.published_at} />
                </div>
              </div>

              <div className="grid gap-3 md:grid-cols-2">
                <ToggleField label="Featured" checked={Boolean(form.data.featured)} onChange={(event) => form.setData('featured', event.target.checked)} help="Highlight this lesson in featured academy surfaces." error={form.errors.featured} />
                <ToggleField label="Active" checked={Boolean(form.data.active)} onChange={(event) => form.setData('active', event.target.checked)} help="Keep inactive lessons hidden until the draft is ready." error={form.errors.active} />
              </div>
            </SectionCard>

            <SectionCard id="lesson-seo" eyebrow="SEO" title="Search metadata" description="Keep the lesson search-ready without stuffing the headline.">
              <div className="grid gap-4 md:grid-cols-2">
                <TextField label="SEO title" value={form.data.seo_title} onChange={(event) => form.setData('seo_title', event.target.value)} error={form.errors.seo_title} maxLength={180} placeholder="Optional search title" />
                <TextField label="Video URL" value={form.data.video_url} onChange={(event) => form.setData('video_url', event.target.value)} error={form.errors.video_url} placeholder="Optional lesson video URL" />
              </div>
              <TextAreaField label="SEO description" value={form.data.seo_description} onChange={(event) => form.setData('seo_description', event.target.value)} error={form.errors.seo_description} rows={4} hint="Keep this tighter than the excerpt and focused on search intent." />
            </SectionCard>

            <SectionCard id="lesson-categories" eyebrow="Lesson categories" title="Create category inline" description="Add lesson categories without leaving the writing flow." actions={<a href={editorContext.categoryManageUrl} className="rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-sm font-semibold text-white">Manage all categories</a>}>
              <div className="grid gap-5 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]">
                <div className="grid gap-3">
                  <div className="grid gap-3 md:grid-cols-2">
                    <input value={categoryDraft.name} onChange={(event) => setCategoryDraft((current) => ({ ...current, name: event.target.value }))} placeholder="Category name" className="rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" />
                    <input value={categoryDraft.slug} onChange={(event) => setCategoryDraft((current) => ({ ...current, slug: event.target.value }))} placeholder="Optional slug" className="rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" />
                  </div>
                  <textarea value={categoryDraft.description} onChange={(event) => setCategoryDraft((current) => ({ ...current, description: event.target.value }))} rows={3} placeholder="Description" className="rounded-[24px] border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" />
                  <div className="flex flex-wrap items-center gap-3">
                    <input type="number" value={categoryDraft.order_num} min="0" onChange={(event) => setCategoryDraft((current) => ({ ...current, order_num: event.target.value }))} className="w-28 rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" />
                    <label className="flex items-center gap-2 text-sm text-slate-300"><input type="checkbox" checked={categoryDraft.active} onChange={(event) => setCategoryDraft((current) => ({ ...current, active: event.target.checked }))} /> Active</label>
                    <button type="button" onClick={() => void createCategory()} disabled={categorySaving} className="rounded-full border border-sky-300/20 bg-sky-400/10 px-4 py-2 text-sm font-semibold text-sky-100">{categorySaving ? 'Creating...' : 'Create category'}</button>
                  </div>
                  {categoryError ? <div className="rounded-2xl border border-rose-300/20 bg-rose-400/10 px-4 py-3 text-sm text-rose-100">{categoryError}</div> : null}
                </div>

                <div className="grid gap-3">
                  {(categories || []).length === 0 ? <div className="rounded-2xl border border-dashed border-white/10 bg-white/[0.02] p-4 text-sm text-slate-500">No lesson categories yet.</div> : categories.map((category) => (
                    <div key={category.id} className="rounded-[24px] border border-white/10 bg-black/20 p-4">
                      <div className="flex items-start justify-between gap-3">
                        <div>
                          <div className="text-sm font-semibold text-white">{category.name}</div>
                          <div className="mt-1 text-xs uppercase tracking-[0.14em] text-slate-500">{category.slug}</div>
                          {category.description ? <p className="mt-2 text-sm leading-6 text-slate-400">{category.description}</p> : null}
                        </div>
                        <a href={category.edit_url} className="rounded-full border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs font-semibold text-white">Edit</a>
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            </SectionCard>
          </div>

          <div className="space-y-6 xl:sticky xl:top-6 xl:self-start">
            <SectionCard id="lesson-cover" eyebrow="Cover image" title="Hero asset" description="Use drag and drop for the lesson image, or paste a direct URL when you already have one.">
              <div className="grid gap-4">
                <WorldMediaUploadField
                  label="Lesson cover"
                  slot="cover"
                  value={form.data.cover_image}
                  previewUrl={coverPreviewUrl}
                  emptyLabel="Drop a lesson cover"
                  helperText="Upload the hero image directly to object storage. A wide landscape image works best for academy cards, previews, and social sharing."
                  uploadUrl={editorContext.coverUploadUrl}
                  deleteUrl={editorContext.coverDeleteUrl}
                  onChange={({ path, url }) => {
                    setStagedCoverPath(path || '')
                    form.setData('cover_image', path || '')
                    setCoverPreviewUrl(url || '')
                  }}
                  isTemporaryValue={Boolean(stagedCoverPath) && form.data.cover_image === stagedCoverPath}
                />
                <FieldError message={form.errors.cover_image} />

                <label className="grid gap-2 text-sm text-slate-300">
                  <span className="text-[11px] font-semibold uppercase tracking-[0.16em] text-slate-500">Advanced cover path or URL</span>
                  <input value={form.data.cover_image} onChange={(event) => handleManualCoverChange(event.target.value)} placeholder="Optional external URL or stored object path" className="rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" />
                  <span className="text-xs leading-5 text-slate-500">Keep this for migrations, imported lessons, or when you already know the exact asset path to use.</span>
                </label>
              </div>
            </SectionCard>

            <SectionCard id="lesson-preview" eyebrow="Preview" title="Lesson snapshot" description="A quick view of what editors and visitors will scan first.">
              <div className="overflow-hidden rounded-[24px] border border-white/10 bg-black/30">
                {coverPreviewUrl ? (
                  <img src={coverPreviewUrl} alt="Lesson cover preview" className="h-56 w-full object-cover" />
                ) : (
                  <div className="flex h-56 items-center justify-center px-6 text-center text-sm text-slate-500">No cover image selected yet.</div>
                )}
              </div>

              <div className="mt-4 rounded-[24px] border border-white/10 bg-black/20 p-4">
                <p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">Lesson summary</p>
                <h3 className="mt-3 text-2xl font-semibold tracking-[-0.04em] text-white">{form.data.title || 'Untitled lesson'}</h3>
                <p className="mt-2 text-sm leading-7 text-slate-400">{form.data.excerpt || 'Add a concise excerpt to frame the lesson before someone opens it.'}</p>
                <dl className="mt-4 grid grid-cols-2 gap-3 text-xs text-slate-400">
                  <div className="rounded-2xl border border-white/10 bg-white/[0.03] px-3 py-2"><dt className="uppercase tracking-[0.16em] text-slate-500">Difficulty</dt><dd className="mt-1 text-sm text-white">{form.data.difficulty || '—'}</dd></div>
                  <div className="rounded-2xl border border-white/10 bg-white/[0.03] px-3 py-2"><dt className="uppercase tracking-[0.16em] text-slate-500">Access</dt><dd className="mt-1 text-sm text-white">{form.data.access_level || '—'}</dd></div>
                  <div className="rounded-2xl border border-white/10 bg-white/[0.03] px-3 py-2"><dt className="uppercase tracking-[0.16em] text-slate-500">Reading</dt><dd className="mt-1 text-sm text-white">{form.data.reading_minutes || '—'} min</dd></div>
                  <div className="rounded-2xl border border-white/10 bg-white/[0.03] px-3 py-2"><dt className="uppercase tracking-[0.16em] text-slate-500">Body</dt><dd className="mt-1 text-sm text-white">{bodyWordCount.toLocaleString()} words</dd></div>
                </dl>
              </div>
            </SectionCard>
          </div>
        </div>

        <div className="flex flex-wrap gap-3 rounded-[28px] border border-white/10 bg-white/[0.03] p-5">
          <button type="submit" disabled={form.processing} className="rounded-full border border-sky-300/25 bg-sky-300/12 px-5 py-3 text-sm font-semibold text-sky-100">{form.processing ? 'Saving...' : 'Save lesson'}</button>
          <Link href={indexUrl} className="rounded-full border border-white/10 bg-white/[0.04] px-5 py-3 text-sm font-semibold text-white">Back</Link>
          {destroyUrl ? <button type="button" onClick={deleteLesson} className="rounded-full border border-rose-300/20 bg-rose-300/10 px-5 py-3 text-sm font-semibold text-rose-100">Delete</button> : null}
        </div>
      </form>

      <JsonImportDialog
        open={jsonImportOpen}
        value={jsonImportValue}
        error={jsonImportError}
        onChange={(nextValue) => {
          setJsonImportValue(nextValue)
          if (jsonImportError) {
            setJsonImportError('')
          }
        }}
        onClose={() => {
          setJsonImportOpen(false)
          setJsonImportError('')
        }}
        onApply={applyJsonImport}
      />
    </AdminLayout>
  )
}