import React, { useState, useMemo, useRef, useCallback, useEffect } from 'react'
import { usePage, Link } from '@inertiajs/react'
import StudioLayout from '../../Layouts/StudioLayout'
import RichTextEditor from '../../components/forum/RichTextEditor'
import TextInput from '../../components/ui/TextInput'
import Button from '../../components/ui/Button'
import Modal from '../../components/ui/Modal'
import FormField from '../../components/ui/FormField'
import Toggle from '../../components/ui/Toggle'
import NovaSelect from '../../components/ui/NovaSelect'
import TagPicker from '../../components/tags/TagPicker'
import SchedulePublishPicker from '../../components/upload/SchedulePublishPicker'
import ArtworkEvolutionSearchPicker from '../../components/artwork/ArtworkEvolutionSearchPicker'

const EDIT_SECTIONS = [
  { id: 'taxonomy', label: 'Category', hint: 'Content type and category path' },
  { id: 'details', label: 'Details', hint: 'Title and description' },
  { id: 'evolution', label: 'Evolution', hint: 'Link an older original artwork' },
  { id: 'ai-assist', label: 'AI Assist', hint: 'Suggestions and similar matches' },
  { id: 'tags', label: 'Tags', hint: 'Search, add, and refine keywords' },
  { id: 'visibility', label: 'Visibility', hint: 'Publishing state' },
]

const TABS = [
  { id: 'details', label: 'Details', icon: 'fa-solid fa-pen-fancy' },
  { id: 'evolution', label: 'Evolution', icon: 'fa-solid fa-code-branch' },
  { id: 'tags', label: 'Tags', icon: 'fa-solid fa-tags' },
  { id: 'taxonomy', label: 'Category', icon: 'fa-solid fa-palette' },
  { id: 'visibility', label: 'Visibility', icon: 'fa-solid fa-eye' },
  { id: 'ai', label: 'AI Assist', icon: 'fa-solid fa-wand-magic-sparkles' },
]

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

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

function formatBytes(bytes) {
  if (!bytes) return '—'
  if (bytes < 1024) return bytes + ' B'
  if (bytes < 1048576) return (bytes / 1024).toFixed(1) + ' KB'
  return (bytes / 1048576).toFixed(1) + ' MB'
}

function getContentTypeVisualKey(slug) {
  const map = { skins: 'skins', wallpapers: 'wallpapers', photography: 'photography', other: 'other', members: 'members' }
  return map[slug] || 'other'
}

function buildCategoryTree(contentTypes) {
  return (contentTypes || []).map((ct) => ({
    ...ct,
    rootCategories: (ct.categories || ct.root_categories || []).map((rc) => ({
      ...rc,
      children: rc.children || [],
    })),
  }))
}

function nextSourceForManualEdit(currentSource) {
  if (currentSource === 'ai_applied' || currentSource === 'ai_generated') return 'mixed'
  if (currentSource === 'mixed') return 'mixed'
  return 'manual'
}

function statusTone(status) {
  switch (status) {
    case 'ready':
      return 'border-emerald-400/30 bg-emerald-400/10 text-emerald-200'
    case 'queued':
    case 'processing':
      return 'border-sky-400/30 bg-sky-400/10 text-sky-200'
    case 'failed':
      return 'border-red-400/30 bg-red-400/10 text-red-200'
    default:
      return 'border-white/10 bg-white/[0.04] text-slate-300'
  }
}

function statusLabel(status) {
  switch (status) {
    case 'queued':
      return 'Queued'
    case 'processing':
      return 'Processing'
    case 'ready':
      return 'Ready'
    case 'failed':
      return 'Failed'
    case 'pending':
      return 'Pending'
    default:
      return 'Not analyzed'
  }
}

function visibilityLabel(value) {
  switch (value) {
    case 'unlisted':
      return 'Unlisted'
    case 'private':
      return 'Private'
    default:
      return 'Public'
  }
}

function normalizeContributorCredits(contributorIds = [], contributorCredits = {}) {
  const normalized = {}
  const ids = Array.isArray(contributorIds)
    ? contributorIds.map((id) => Number(id)).filter((id) => Number.isFinite(id) && id > 0)
    : []

  ids.forEach((id) => {
    const current = contributorCredits?.[id] || contributorCredits?.[String(id)] || {}
    normalized[id] = {
      creditRole: typeof current.creditRole === 'string' ? current.creditRole : '',
      isPrimary: Boolean(current.isPrimary),
    }
  })

  const leadIds = Object.entries(normalized)
    .filter(([, value]) => value.isPrimary)
    .map(([id]) => Number(id))

  if (leadIds.length > 1) {
    leadIds.slice(1).forEach((id) => {
      normalized[id] = {
        ...normalized[id],
        isPrimary: false,
      }
    })
  }

  return normalized
}

function mapContributorCredits(contributorCredits = []) {
  return (Array.isArray(contributorCredits) ? contributorCredits : []).reduce((accumulator, contributor) => {
    const userId = Number(contributor?.user_id)
    if (!Number.isFinite(userId) || userId <= 0) return accumulator

    accumulator[userId] = {
      creditRole: typeof contributor?.credit_role === 'string' ? contributor.credit_role : '',
      isPrimary: Boolean(contributor?.is_primary),
    }

    return accumulator
  }, {})
}

// ─── Sub-components ──────────────────────────────────────────────────────────

/** Glass-morphism section card (Nova theme) */
function Section({ children, className = '', id = undefined }) {
  return (
    <section id={id} className={`scroll-mt-24 bg-nova-900/60 border border-white/10 rounded-2xl p-6 ${className}`}>
      {children}
    </section>
  )
}

/** Section heading */
function SectionTitle({ icon, children }) {
  return (
    <h3 className="flex items-center gap-2 text-xs font-semibold uppercase tracking-wider text-slate-400 mb-4">
      {icon && <i className={`${icon} text-accent/70 text-[11px]`} />}
      {children}
    </h3>
  )
}

function InlineAiButton({ children, onClick, disabled = false, loading = false }) {
  return (
    <button
      type="button"
      onClick={onClick}
      disabled={disabled}
      className="inline-flex items-center gap-1 rounded-full border border-sky-400/20 bg-sky-400/10 px-2.5 py-1 text-[11px] font-semibold text-sky-200 transition hover:bg-sky-400/15 disabled:cursor-not-allowed disabled:opacity-50"
    >
      <span>{loading ? '...' : '✦'}</span>
      <span>{children}</span>
    </button>
  )
}

function FieldLabel({ label, actionLabel, onAction, disabled = false, loading = false }) {
  return (
    <div className="flex items-center justify-between gap-3">
      <span>{label}</span>
      <InlineAiButton onClick={onAction} disabled={disabled} loading={loading}>{actionLabel}</InlineAiButton>
    </div>
  )
}

function RightRailCard({ title, children, className = '' }) {
  return (
    <div className={`rounded-2xl border border-white/10 bg-[radial-gradient(circle_at_top,_rgba(148,163,184,0.16),_rgba(15,23,42,0.92)_62%)] p-4 ${className}`}>
      <h3 className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-400">{title}</h3>
      <div className="mt-3">{children}</div>
    </div>
  )
}

// ─── Main Component ──────────────────────────────────────────────────────────

export default function StudioArtworkEdit() {
  const { props } = usePage()
  const { artwork, contentTypes: rawContentTypes } = props
  const groupOptions = Array.isArray(props.groupOptions) ? props.groupOptions : []
  const evolutionRelationTypes = Array.isArray(props.evolutionRelationTypes) ? props.evolutionRelationTypes : []
  const initialEvolutionRelation = artwork?.evolution_relation || null
  const contributorOptionsByGroup = props.contributorOptionsByGroup && typeof props.contributorOptionsByGroup === 'object'
    ? props.contributorOptionsByGroup
    : {}

  const contentTypes = useMemo(() => buildCategoryTree(rawContentTypes || []), [rawContentTypes])

  // ── State ──────────────────────────────────────────────────────────────────
  const [contentTypeId, setContentTypeId] = useState(artwork?.content_type_id || null)
  const [categoryId, setCategoryId] = useState(artwork?.parent_category_id || null)
  const [subCategoryId, setSubCategoryId] = useState(artwork?.sub_category_id || null)
  const [title, setTitle] = useState(artwork?.title || '')
  const [description, setDescription] = useState(artwork?.description || '')
  const [tagSlugs, setTagSlugs] = useState(() => (artwork?.tags || []).map((t) => t.slug || t.name))
  const [visibility, setVisibility] = useState(artwork?.visibility || (artwork?.is_public ? 'public' : 'private'))
  const [publishMode, setPublishMode] = useState(artwork?.publish_mode || (artwork?.artwork_status === 'scheduled' ? 'schedule' : 'now'))
  const [scheduledAt, setScheduledAt] = useState(artwork?.publish_at || null)
  const [groupSlug, setGroupSlug] = useState(artwork?.group_slug || '')
  const [primaryAuthorUserId, setPrimaryAuthorUserId] = useState(artwork?.primary_author_user_id || null)
  const [contributorUserIds, setContributorUserIds] = useState(() => (Array.isArray(artwork?.contributor_user_ids) ? artwork.contributor_user_ids.map((id) => Number(id)).filter((id) => Number.isFinite(id) && id > 0) : []))
  const [contributorCredits, setContributorCredits] = useState(() => normalizeContributorCredits(artwork?.contributor_user_ids || [], mapContributorCredits(artwork?.contributor_credits || [])))
  const [titleSource, setTitleSource] = useState(artwork?.title_source || 'manual')
  const [descriptionSource, setDescriptionSource] = useState(artwork?.description_source || 'manual')
  const [tagsSource, setTagsSource] = useState(artwork?.tags_source || 'manual')
  const [categorySource, setCategorySource] = useState(artwork?.category_source || 'manual')
  const [evolutionTarget, setEvolutionTarget] = useState(initialEvolutionRelation?.target_artwork || null)
  const [evolutionRelationType, setEvolutionRelationType] = useState(initialEvolutionRelation?.relation_type || evolutionRelationTypes[0]?.value || 'remake_of')
  const [evolutionNote, setEvolutionNote] = useState(initialEvolutionRelation?.note || '')
  const [saving, setSaving] = useState(false)
  const [saved, setSaved] = useState(false)
  const [errors, setErrors] = useState({})
  const [aiData, setAiData] = useState(null)
  const [aiLoading, setAiLoading] = useState(false)
  const [aiAction, setAiAction] = useState('')
  const [aiDirect, setAiDirect] = useState(false)
  const [isAiPanelOpen, setIsAiPanelOpen] = useState(true)
  const [isAiDebugOpen, setIsAiDebugOpen] = useState(false)
  const [lastAiRequest, setLastAiRequest] = useState(null)
  const [selectedAiTags, setSelectedAiTags] = useState([])
  const [activeTab, setActiveTab] = useState('details')
  const [isCategoryChooserOpen, setIsCategoryChooserOpen] = useState(() => !artwork?.parent_category_id)
  const userTimezone = useMemo(() => artwork?.artwork_timezone || Intl.DateTimeFormat().resolvedOptions().timeZone, [artwork?.artwork_timezone])

  // File replace
  const fileInputRef = useRef(null)
  const [replacing, setReplacing] = useState(false)
  const [thumbUrl, setThumbUrl] = useState(artwork?.thumb_url_lg || artwork?.thumb_url || null)
  const [fileMeta, setFileMeta] = useState({
    name: artwork?.file_name || '—',
    size: artwork?.file_size || 0,
    width: artwork?.width || 0,
    height: artwork?.height || 0,
  })
  const [versionCount, setVersionCount] = useState(artwork?.version_count ?? 1)
  const [requiresReapproval, setRequiresReapproval] = useState(artwork?.requires_reapproval ?? false)
  const [changeNote, setChangeNote] = useState('')
  const [showChangeNote, setShowChangeNote] = useState(false)

  // Version history
  const [showHistory, setShowHistory] = useState(false)
  const [historyData, setHistoryData] = useState(null)
  const [historyLoading, setHistoryLoading] = useState(false)
  const [restoring, setRestoring] = useState(null)

  // ── Derived ────────────────────────────────────────────────────────────────
  const selectedCT = contentTypes.find((ct) => ct.id === contentTypeId) || null
  const rootCategories = selectedCT?.rootCategories || []
  const selectedRoot = rootCategories.find((c) => c.id === categoryId) || null
  const subCategories = selectedRoot?.children || []
  const selectedGroupOption = useMemo(() => groupOptions.find((group) => String(group.slug || '') === String(groupSlug || '')) || null, [groupOptions, groupSlug])
  const currentContributorOptions = useMemo(() => {
    const selectedSlug = String(groupSlug || '')
    return Array.isArray(contributorOptionsByGroup?.[selectedSlug]) ? contributorOptionsByGroup[selectedSlug] : []
  }, [contributorOptionsByGroup, groupSlug])
  const aiStatus = aiData?.status || artwork?.ai_status || 'not_analyzed'
  const aiSuggestedTags = useMemo(() => (aiData?.tag_suggestions || []).map((item) => item.tag).filter(Boolean), [aiData])
  const selectedLeafCategoryId = subCategoryId || categoryId || null
  const visibilitySummary = publishMode === 'schedule'
    ? `Scheduled as ${visibilityLabel(visibility)}`
    : visibilityLabel(visibility)
  const heroMeta = [
    selectedCT?.name || 'No content type',
    selectedRoot?.name || 'No root category',
    subCategoryId ? subCategories.find((item) => item.id === subCategoryId)?.name : null,
  ].filter(Boolean)
  const publishingIdentityOptions = useMemo(() => {
    const personalOption = {
      value: '',
      label: 'Personal profile',
      icon: <i className="fa-solid fa-user text-[11px] text-sky-200" aria-hidden="true" />,
      contextLabel: 'Publish under your own creator identity',
    }

    const groupItems = groupOptions.map((group) => ({
      value: group.slug,
      label: group.name,
      icon: <i className="fa-solid fa-users text-[11px] text-violet-200" aria-hidden="true" />,
      contextLabel: 'Publish under the shared group identity',
    }))

    return [personalOption, ...groupItems]
  }, [groupOptions])
  const primaryAuthorOptions = useMemo(() => currentContributorOptions.map((user) => ({
    value: Number(user.id),
    label: user.name || user.username,
    username: user.username,
    avatarUrl: user.avatar_url || null,
  })), [currentContributorOptions])
  const selectedEvolutionType = evolutionRelationTypes.find((option) => String(option.value) === String(evolutionRelationType)) || evolutionRelationTypes[0] || null

  // ── Handlers ───────────────────────────────────────────────────────────────
  const handleContentTypeChange = (id) => {
    setContentTypeId(id)
    setCategoryId(null)
    setSubCategoryId(null)
    setIsCategoryChooserOpen(true)
    setCategorySource((current) => nextSourceForManualEdit(current))
  }

  const handleCategoryChange = (id) => {
    setCategoryId(id)
    setSubCategoryId(null)
    setIsCategoryChooserOpen(false)
    setCategorySource((current) => nextSourceForManualEdit(current))
  }

  const handleSubCategoryChange = (id) => {
    setSubCategoryId(id)
    setCategorySource((current) => nextSourceForManualEdit(current))
  }

  const handleTitleChange = (e) => {
    setTitle(e.target.value)
    setTitleSource((current) => nextSourceForManualEdit(current))
  }

  const handleDescriptionChange = (value) => {
    setDescription(value)
    setDescriptionSource((current) => nextSourceForManualEdit(current))
  }

  const handleTagChange = (nextTags) => {
    setTagSlugs(nextTags)
    setTagsSource((current) => nextSourceForManualEdit(current))
  }

  const loadAiData = useCallback(async (silent = false) => {
    if (!artwork?.id) return
    if (!silent) setAiLoading(true)
    try {
      const res = await fetch(`/api/studio/artworks/${artwork.id}/ai`, {
        headers: { Accept: 'application/json', 'X-CSRF-TOKEN': getCsrfToken() },
        credentials: 'same-origin',
      })
      if (!res.ok) return
      const data = await res.json()
      setAiData(data.data || null)
      setSelectedAiTags((data.data?.tag_suggestions || []).map((item) => item.tag).filter(Boolean))
    } catch (err) {
      console.error('AI assist load failed:', err)
    } finally {
      if (!silent) setAiLoading(false)
    }
  }, [artwork?.id])

  const syncCurrentPayload = useCallback((current) => {
    if (!current) return
    setTitle(current.title || '')
    setDescription(current.description || '')
    setTagSlugs(Array.isArray(current.tags) ? current.tags : [])
    setContentTypeId(current.content_type_id || null)
    setCategoryId(current.category_id || null)
    setSubCategoryId(null)
    setTitleSource(current.sources?.title || 'manual')
    setDescriptionSource(current.sources?.description || 'manual')
    setTagsSource(current.sources?.tags || 'manual')
    setCategorySource(current.sources?.category || 'manual')
  }, [])

  const trackAiEvent = useCallback(async (eventType, meta = {}) => {
    if (!artwork?.id) return
    try {
      await fetch(`/api/studio/artworks/${artwork.id}/ai/events`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-CSRF-TOKEN': getCsrfToken() },
        credentials: 'same-origin',
        body: JSON.stringify({ event_type: eventType, meta }),
      })
    } catch (err) {
      console.error('AI event track failed:', err)
    }
  }, [artwork?.id])

  const triggerAi = useCallback(async (action = 'analyze', options = {}) => {
    if (!artwork?.id) return
    setAiAction(action)
    try {
      const direct = typeof options.direct === 'boolean' ? options.direct : aiDirect
      const intent = options.intent || 'analyze'
      const requestBody = { direct, intent }
      setLastAiRequest({
        endpoint: `/api/studio/artworks/${artwork.id}/ai/${action}`,
        method: 'POST',
        body: requestBody,
        at: new Date().toISOString(),
      })
      const res = await fetch(`/api/studio/artworks/${artwork.id}/ai/${action}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-CSRF-TOKEN': getCsrfToken() },
        credentials: 'same-origin',
        body: JSON.stringify(requestBody),
      })
      if (res.ok) {
        const data = await res.json()
        if (direct && data?.data) {
          setAiData(data.data)
        } else {
          await loadAiData(true)
        }
      }
    } catch (err) {
      console.error('AI assist request failed:', err)
    } finally {
      setAiAction('')
    }
  }, [aiDirect, artwork?.id, loadAiData])

  const persistAiAction = useCallback(async (payload) => {
    if (!artwork?.id) return
    setAiAction('apply')
    try {
      setLastAiRequest({
        endpoint: `/api/studio/artworks/${artwork.id}/ai/apply`,
        method: 'POST',
        body: payload,
        at: new Date().toISOString(),
      })
      const res = await fetch(`/api/studio/artworks/${artwork.id}/ai/apply`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-CSRF-TOKEN': getCsrfToken() },
        credentials: 'same-origin',
        body: JSON.stringify(payload),
      })
      if (res.ok) {
        const data = await res.json()
        if (data?.data) {
          setAiData(data.data)
          syncCurrentPayload(data.data.current)
          setSelectedAiTags((data.data.tag_suggestions || []).map((item) => item.tag).filter(Boolean))
        } else {
          await loadAiData(true)
        }
      }
    } catch (err) {
      console.error('AI assist apply failed:', err)
    } finally {
      setAiAction('')
    }
  }, [artwork?.id, loadAiData, syncCurrentPayload])

  const copyText = useCallback(async (value) => {
    if (!value) return
    try {
      await window.navigator?.clipboard?.writeText(value)
      trackAiEvent('suggestion_copied', { length: value.length })
    } catch (err) {
      console.error('Clipboard write failed:', err)
    }
  }, [trackAiEvent])

  const applyTitleSuggestion = useCallback((value, mode = 'replace') => {
    persistAiAction({ title: value, title_mode: mode })
  }, [persistAiAction])

  const applyDescriptionSuggestion = useCallback((value, mode = 'replace') => {
    persistAiAction({ description: value, description_mode: mode })
  }, [persistAiAction])

  const applyTagSuggestions = useCallback((values, mode = 'add') => {
    const normalized = Array.isArray(values) ? values.filter(Boolean) : []
    if (normalized.length === 0) return
    persistAiAction({ tags: normalized, tag_mode: mode })
  }, [persistAiAction])

  const applyCategorySuggestion = useCallback((suggestion, mode = 'both') => {
    if (!suggestion) return
    const payload = {}
    if (mode === 'content_type' || mode === 'both') {
      payload.content_type_id = suggestion.content_type_id || suggestion.id || null
    }
    if (mode === 'category' || mode === 'both') {
      payload.category_id = suggestion.root_category_id || suggestion.id || null
    }
    persistAiAction(payload)
  }, [persistAiAction])

  const toggleSuggestedTag = useCallback((tag) => {
    if (!tag) return
    setSelectedAiTags((current) => current.includes(tag)
      ? current.filter((item) => item !== tag)
      : [...current, tag])
  }, [])

  const handleImproveAll = useCallback(() => {
    if (aiStatus !== 'ready') {
      triggerAi('analyze', { intent: 'analyze' })
      return
    }
    const bestTitle = aiData?.title_suggestions?.[0]?.text
    const bestDescription = aiData?.description_suggestions?.find((item) => item.variant === 'normal')?.text
      || aiData?.description_suggestions?.[0]?.text
    const bestCategory = aiData?.category
    const payload = {}
    if (bestTitle) {
      payload.title = bestTitle
      payload.title_mode = 'replace'
    }
    if (bestDescription) {
      payload.description = bestDescription
      payload.description_mode = 'replace'
    }
    if (aiSuggestedTags.length > 0) {
      payload.tags = aiSuggestedTags
      payload.tag_mode = 'add'
    }
    if (bestCategory?.content_type_id) {
      payload.content_type_id = bestCategory.content_type_id
    }
    if (bestCategory?.root_category_id || bestCategory?.id) {
      payload.category_id = bestCategory.root_category_id || bestCategory.id
    }
    if (Object.keys(payload).length > 0) {
      persistAiAction(payload)
    }
    trackAiEvent('improve_all_applied', {
      applied_title: Boolean(bestTitle),
      applied_description: Boolean(bestDescription),
      applied_tags: aiSuggestedTags.length > 0,
      applied_category: Boolean(bestCategory),
    })
  }, [aiData, aiStatus, aiSuggestedTags, persistAiAction, trackAiEvent, triggerAi])

  const aiDebugPayload = useMemo(() => ({
    last_editor_request: lastAiRequest,
    stored_debug: aiData?.debug || null,
  }), [aiData?.debug, lastAiRequest])

  const requestAiIntent = useCallback((intent, action = null) => {
    const nextAction = action || (aiStatus === 'ready' ? 'regenerate' : 'analyze')
    trackAiEvent('intent_requested', { intent, action: nextAction })
    triggerAi(nextAction, { intent })
  }, [aiStatus, trackAiEvent, triggerAi])

  const toggleAiPanel = useCallback(() => {
    setIsAiPanelOpen((current) => {
      const next = !current
      trackAiEvent('panel_toggled', { open: next })
      return next
    })
  }, [trackAiEvent])

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

  useEffect(() => {
    if (aiStatus !== 'queued' && aiStatus !== 'processing') return undefined
    const timer = window.setInterval(() => loadAiData(true), 4000)
    return () => window.clearInterval(timer)
  }, [aiStatus, loadAiData])

  useEffect(() => {
    const selectedSlug = String(groupSlug || '')
    if (!selectedSlug) {
      if (primaryAuthorUserId || contributorUserIds.length > 0 || Object.keys(contributorCredits || {}).length > 0) {
        setPrimaryAuthorUserId(null)
        setContributorUserIds([])
        setContributorCredits({})
      }
      return
    }

    const validGroup = groupOptions.some((group) => String(group.slug || '') === selectedSlug)
    if (!validGroup) {
      setGroupSlug('')
      setPrimaryAuthorUserId(null)
      setContributorUserIds([])
      setContributorCredits({})
      return
    }

    const validContributorIds = currentContributorOptions.map((user) => Number(user.id)).filter((id) => Number.isFinite(id) && id > 0)
    const nextPrimaryAuthorId = validContributorIds.includes(Number(primaryAuthorUserId))
      ? Number(primaryAuthorUserId)
      : (validContributorIds[0] || null)

    const nextContributorIds = contributorUserIds
      .map((id) => Number(id))
      .filter((id) => validContributorIds.includes(id) && id !== nextPrimaryAuthorId)

    const nextContributorCredits = normalizeContributorCredits(nextContributorIds, contributorCredits)
    const primaryChanged = (primaryAuthorUserId ? Number(primaryAuthorUserId) : null) !== nextPrimaryAuthorId
    const contributorsChanged = nextContributorIds.length !== contributorUserIds.length || nextContributorIds.some((id, index) => id !== contributorUserIds[index])
    const contributorCreditsChanged = JSON.stringify(nextContributorCredits) !== JSON.stringify(normalizeContributorCredits(contributorUserIds, contributorCredits))

    if (primaryChanged) setPrimaryAuthorUserId(nextPrimaryAuthorId)
    if (contributorsChanged) setContributorUserIds(nextContributorIds)
    if (contributorCreditsChanged) setContributorCredits(nextContributorCredits)
  }, [groupSlug, groupOptions, currentContributorOptions, primaryAuthorUserId, contributorUserIds, contributorCredits])

  const handleSave = useCallback(async () => {
    setSaving(true)
    setSaved(false)
    setErrors({})
    try {
      const payload = {
        title,
        description,
        visibility,
        mode: publishMode,
        publish_at: publishMode === 'schedule' ? scheduledAt : null,
        timezone: userTimezone,
        group: groupSlug || null,
        primary_author_user_id: groupSlug ? primaryAuthorUserId : null,
        contributor_user_ids: groupSlug ? contributorUserIds : [],
        contributor_credits: groupSlug
          ? contributorUserIds.map((id) => ({
            user_id: id,
            credit_role: contributorCredits?.[id]?.creditRole?.trim() ? contributorCredits[id].creditRole.trim() : null,
            is_primary: Boolean(contributorCredits?.[id]?.isPrimary),
          }))
          : [],
        content_type_id: contentTypeId,
        category_id: selectedLeafCategoryId,
        tags: tagSlugs,
        title_source: titleSource,
        description_source: descriptionSource,
        tags_source: tagsSource,
        category_source: categorySource,
        evolution_target_artwork_id: evolutionTarget?.id || null,
        evolution_relation_type: evolutionTarget ? evolutionRelationType : null,
        evolution_note: evolutionTarget ? evolutionNote : null,
      }
      const res = await fetch(`/api/studio/artworks/${artwork.id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-CSRF-TOKEN': getCsrfToken() },
        credentials: 'same-origin',
        body: JSON.stringify(payload),
      })
      if (res.ok) {
        const data = await res.json()
        const updatedArtwork = data?.artwork || null
        const updatedEvolutionRelation = data?.evolution_relation || updatedArtwork?.evolution_relation || null
        if (updatedArtwork) {
          setVisibility(updatedArtwork.visibility || visibility)
          setPublishMode(updatedArtwork.publish_mode || 'now')
          setScheduledAt(updatedArtwork.publish_at || null)
          setGroupSlug(updatedArtwork.group_slug || '')
          setPrimaryAuthorUserId(updatedArtwork.primary_author_user_id || null)
          setContributorUserIds(Array.isArray(updatedArtwork.contributor_user_ids) ? updatedArtwork.contributor_user_ids.map((id) => Number(id)).filter((id) => Number.isFinite(id) && id > 0) : [])
          setContributorCredits(normalizeContributorCredits(updatedArtwork.contributor_user_ids || [], mapContributorCredits(updatedArtwork.contributor_credits || [])))
        }
        setEvolutionTarget(updatedEvolutionRelation?.target_artwork || null)
        setEvolutionRelationType(updatedEvolutionRelation?.relation_type || evolutionRelationTypes[0]?.value || 'remake_of')
        setEvolutionNote(updatedEvolutionRelation?.note || '')
        setSaved(true)
        setTimeout(() => setSaved(false), 3000)
      } else {
        const data = await res.json()
        if (data.errors) setErrors(data.errors)
      }
    } catch (err) {
      console.error('Save failed:', err)
    } finally {
      setSaving(false)
    }
  }, [title, description, visibility, publishMode, scheduledAt, userTimezone, groupSlug, primaryAuthorUserId, contributorUserIds, contributorCredits, contentTypeId, selectedLeafCategoryId, tagSlugs, titleSource, descriptionSource, tagsSource, categorySource, evolutionTarget, evolutionRelationType, evolutionNote, artwork?.id, evolutionRelationTypes])

  const handleFileReplace = async (e) => {
    const file = e.target.files?.[0]
    if (!file) return
    setReplacing(true)
    try {
      const fd = new FormData()
      fd.append('file', file)
      if (changeNote.trim()) fd.append('change_note', changeNote.trim())
      const res = await fetch(`/api/studio/artworks/${artwork.id}/replace-file`, {
        method: 'POST',
        headers: { Accept: 'application/json', 'X-CSRF-TOKEN': getCsrfToken() },
        credentials: 'same-origin',
        body: fd,
      })
      const data = await res.json()
      if (res.ok && data.thumb_url) {
        setThumbUrl(data.thumb_url)
        setFileMeta({ name: file.name, size: file.size, width: data.width || 0, height: data.height || 0 })
        if (data.version_number) setVersionCount(data.version_number)
        if (typeof data.requires_reapproval !== 'undefined') setRequiresReapproval(data.requires_reapproval)
        setChangeNote('')
        setShowChangeNote(false)
      } else {
        alert(data.error || 'File replacement failed.')
      }
    } catch (err) {
      console.error('File replace failed:', err)
    } finally {
      setReplacing(false)
      if (fileInputRef.current) fileInputRef.current.value = ''
    }
  }

  const loadVersionHistory = async () => {
    setHistoryLoading(true)
    setShowHistory(true)
    try {
      const res = await fetch(`/api/studio/artworks/${artwork.id}/versions`, {
        headers: { Accept: 'application/json', 'X-CSRF-TOKEN': getCsrfToken() },
        credentials: 'same-origin',
      })
      setHistoryData(await res.json())
    } catch (err) {
      console.error('Failed to load version history:', err)
    } finally {
      setHistoryLoading(false)
    }
  }

  const handleRestoreVersion = async (versionId) => {
    if (!window.confirm('Restore this version? A copy will become the new current version.')) return
    setRestoring(versionId)
    try {
      const res = await fetch(`/api/studio/artworks/${artwork.id}/restore/${versionId}`, {
        method: 'POST',
        headers: { Accept: 'application/json', 'X-CSRF-TOKEN': getCsrfToken() },
        credentials: 'same-origin',
      })
      const data = await res.json()
      if (res.ok && data.success) {
        setVersionCount((n) => n + 1)
        setShowHistory(false)
      } else {
        alert(data.error || 'Restore failed.')
      }
    } catch (err) {
      console.error('Restore failed:', err)
    } finally {
      setRestoring(null)
    }
  }

  // ── Render ─────────────────────────────────────────────────────────────────
  return (
    <StudioLayout title="Edit Artwork">

      {/* ── Page Header ── */}
      <div className="flex items-center justify-between gap-4 mb-4">
        <div className="flex items-center gap-4 min-w-0">
          <Link
            href="/studio/artworks"
            className="flex items-center justify-center w-9 h-9 rounded-xl border border-white/10 text-slate-400 hover:text-white hover:bg-white/5 transition-all shrink-0"
            aria-label="Back to artworks"
          >
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
              <path d="M10 3L5 8l5 5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </Link>
          <div className="min-w-0">
            <h1 className="text-lg font-bold text-white truncate">
              {title || 'Untitled artwork'}
            </h1>
            <div className="mt-1 flex flex-wrap items-center gap-2 text-xs text-slate-500">
              <span>Editing</span>
              <span className="h-1 w-1 rounded-full bg-slate-600" />
              <span className={publishMode === 'schedule' ? 'text-sky-300' : visibility === 'private' ? 'text-amber-400' : 'text-emerald-400'}>
                {visibilitySummary}
              </span>
              {heroMeta.map((item) => (
                <React.Fragment key={item}>
                  <span className="h-1 w-1 rounded-full bg-slate-600" />
                  <span>{item}</span>
                </React.Fragment>
              ))}
            </div>
          </div>
        </div>
      </div>

      {/* ── Two-column Layout ── */}
      <div className="grid grid-cols-1 gap-6 items-start xl:grid-cols-[300px_minmax(0,1fr)]">

        {/* ─────────── LEFT SIDEBAR ─────────── */}
        <div className="space-y-4 xl:sticky xl:top-6 xl:max-h-[calc(100vh-48px)] xl:overflow-y-auto">

          {/* Preview Card */}
          <Section>
            <SectionTitle icon="fa-solid fa-image">Preview</SectionTitle>

            {/* Thumbnail */}
            <div className="relative aspect-square rounded-xl overflow-hidden bg-white/5 border border-white/10 mb-4">
              {thumbUrl ? (
                <img
                  src={thumbUrl}
                  alt={title || 'Artwork preview'}
                  className="w-full h-full object-cover"
                />
              ) : (
                <div className="w-full h-full flex items-center justify-center text-slate-600">
                  <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" aria-hidden="true">
                    <rect x="3" y="3" width="18" height="18" rx="2" />
                    <circle cx="8.5" cy="8.5" r="1.5" fill="currentColor" />
                    <path d="M21 15l-5-5L5 21" />
                  </svg>
                </div>
              )}
              {replacing && (
                <div className="absolute inset-0 bg-black/60 flex items-center justify-center">
                  <div className="w-7 h-7 border-2 border-accent/30 border-t-accent rounded-full animate-spin" />
                </div>
              )}
            </div>

            {/* File Metadata */}
            <div className="space-y-3">
              <p className="text-sm font-medium text-white truncate" title={fileMeta.name}>{fileMeta.name}</p>
              <div className="flex flex-wrap gap-x-3 gap-y-1 text-[11px] text-slate-500">
                {fileMeta.width > 0 && (
                  <span className="flex items-center gap-1">
                    <svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" className="text-slate-600" aria-hidden="true">
                      <path d="M2 3a1 1 0 011-1h10a1 1 0 011 1v10a1 1 0 01-1 1H3a1 1 0 01-1-1V3zm2 1v8h8V4H4z" />
                    </svg>
                    {fileMeta.width} &times; {fileMeta.height}
                  </span>
                )}
                <span className="flex items-center gap-1">
                  <svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" className="text-slate-600" aria-hidden="true">
                    <path d="M4 1.5a.5.5 0 00-1 0V3H1.5a.5.5 0 000 1h11a.5.5 0 000-1H11V1.5a.5.5 0 00-1 0V3H6V1.5a.5.5 0 00-1 0V3H4V1.5z" />
                    <path d="M1.5 5v8.5A1.5 1.5 0 003 15h10a1.5 1.5 0 001.5-1.5V5h-13z" />
                  </svg>
                  {formatBytes(fileMeta.size)}
                </span>
              </div>

              {/* Version + History */}
              <div className="flex items-center gap-2 pt-1">
                <span className="inline-flex items-center gap-1 text-[10px] font-bold text-accent bg-accent/15 px-2 py-0.5 rounded-full border border-accent/20">
                  v{versionCount}
                </span>
                <button
                  type="button"
                  onClick={loadVersionHistory}
                  className="inline-flex items-center gap-1.5 text-[11px] text-slate-400 hover:text-accent transition-colors"
                >
                  <svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
                    <path fillRule="evenodd" d="M8 3.5a4.5 4.5 0 00-4.04 2.51.75.75 0 01-1.34-.67A6 6 0 1114 8a.75.75 0 01-1.5 0A4.5 4.5 0 008 3.5z" clipRule="evenodd" />
                    <path fillRule="evenodd" d="M4.75.75a.75.75 0 00-.75.75v3.5c0 .414.336.75.75.75h3.5a.75.75 0 000-1.5H5.5V1.5a.75.75 0 00-.75-.75z" clipRule="evenodd" />
                  </svg>
                  History
                </button>
              </div>

              {requiresReapproval && (
                <p className="text-[11px] text-amber-400/90 flex items-center gap-1.5 mt-1">
                  <svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
                    <path d="M8.982 1.566a1.13 1.13 0 00-1.964 0L.165 13.233c-.457.778.091 1.767.982 1.767h13.706c.891 0 1.439-.989.982-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 01-1.1 0L7.1 5.995A.905.905 0 018 5zm.002 6a1 1 0 100 2 1 1 0 000-2z" />
                  </svg>
                  Requires re-approval after replace
                </p>
              )}
            </div>

            {/* Replace File */}
            <div className="mt-4 pt-4 border-t border-white/8 space-y-2.5">
              {showChangeNote && (
                <TextInput
                  value={changeNote}
                  onChange={(e) => setChangeNote(e.target.value)}
                  placeholder="Change note (optional)…"
                  size="sm"
                />
              )}
              <div className="flex items-center gap-2">
                <Button
                  variant="secondary"
                  size="xs"
                  loading={replacing}
                  onClick={() => fileInputRef.current?.click()}
                >
                  {replacing ? 'Replacing…' : 'Replace file'}
                </Button>
                {!showChangeNote && (
                  <button
                    type="button"
                    onClick={() => setShowChangeNote(true)}
                    className="text-[11px] text-slate-500 hover:text-white transition-colors"
                  >
                    + note
                  </button>
                )}
              </div>
              <input ref={fileInputRef} type="file" className="hidden" accept="image/*" onChange={handleFileReplace} />
            </div>
          </Section>

          {/* Quick Links */}
          <Section className="py-3 px-4">
            <Link
              href={`/studio/artworks/${artwork?.id}/analytics`}
              className="flex items-center gap-3 py-2 text-sm text-slate-400 hover:text-white transition-colors group"
            >
              <span className="flex items-center justify-center w-8 h-8 rounded-lg bg-white/5 group-hover:bg-accent/15 transition-colors">
                <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor" className="text-slate-500 group-hover:text-accent transition-colors" aria-hidden="true">
                  <path d="M1 11a1 1 0 011-1h2a1 1 0 011 1v3a1 1 0 01-1 1H2a1 1 0 01-1-1v-3zm5-4a1 1 0 011-1h2a1 1 0 011 1v7a1 1 0 01-1 1H7a1 1 0 01-1-1V7zm5-5a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V2z" />
                </svg>
              </span>
              View Analytics
            </Link>
          </Section>
        </div>

        {/* ─────────── RIGHT MAIN FORM ─────────── */}
        <div className="flex flex-col min-h-0">

          {/* ── Tab Nav ── */}
          <div className="sticky top-0 z-30 bg-nova-900/95 backdrop-blur-md flex items-stretch border-b border-white/10 mb-6">
            <div className="flex items-center overflow-x-auto flex-1 min-w-0">
              {TABS.map((tab) => (
                <button
                  key={tab.id}
                  type="button"
                  onClick={() => setActiveTab(tab.id)}
                  className={[
                    'relative flex items-center gap-2 px-4 py-3 text-sm font-medium whitespace-nowrap transition-colors',
                    activeTab === tab.id
                      ? 'text-white after:absolute after:bottom-0 after:left-0 after:right-0 after:h-[2px] after:bg-accent after:rounded-t-full'
                      : 'text-slate-400 hover:text-slate-200',
                  ].join(' ')}
                >
                  <i className={`${tab.icon} text-[11px]`} aria-hidden="true" />
                  {tab.label}
                  {tab.id === 'evolution' && evolutionTarget && (
                    <span className="h-1.5 w-1.5 rounded-full bg-sky-400" />
                  )}
                  {tab.id === 'ai' && aiStatus !== 'not_analyzed' && (
                    <span className={`h-1.5 w-1.5 rounded-full ${aiStatus === 'ready' ? 'bg-emerald-400' : aiStatus === 'failed' ? 'bg-red-400' : 'bg-sky-400'}`} />
                  )}
                </button>
              ))}
            </div>
            <div className="flex items-center gap-2 px-3 flex-shrink-0">
              {saved && (
                <span className="text-xs text-emerald-400 flex items-center gap-1">
                  <svg width="12" height="12" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
                    <path fillRule="evenodd" d="M8 16A8 8 0 108 0a8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L7 8.586 5.707 7.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
                  </svg>
                  Saved
                </span>
              )}
              <Button variant="accent" size="xs" loading={saving} onClick={handleSave}>
                Save
              </Button>
            </div>
          </div>

          {/* ── Category tab ── */}
          {activeTab === 'taxonomy' && (
          <div className="space-y-6">
          <Section id="taxonomy" className="space-y-6">
            <div className="flex flex-col gap-3 lg:flex-row lg:items-end lg:justify-between">
              <div>
                <SectionTitle icon="fa-solid fa-palette">Category</SectionTitle>
                <p className="-mt-2 text-sm text-slate-400">Pick a content type from the left, then choose the best category path on the right. The layout keeps the hierarchy visible instead of stretching into one long wall of chips.</p>
              </div>
              <div className="flex flex-wrap gap-2 text-xs">
                <span className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.03] px-3 py-1.5 text-slate-300">
                  <span className="text-slate-500">Type</span>
                  <span className="font-semibold text-white">{selectedCT?.name || 'Unset'}</span>
                </span>
                <span className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.03] px-3 py-1.5 text-slate-300">
                  <span className="text-slate-500">Path</span>
                  <span className="font-semibold text-white">{selectedRoot?.name || 'Choose category'}</span>
                </span>
              </div>
            </div>

            <div className="grid gap-5 xl:grid-cols-[280px_minmax(0,1fr)]">
              <div className="rounded-2xl border border-white/10 bg-[linear-gradient(180deg,rgba(255,255,255,0.04),rgba(255,255,255,0.02))] p-4">
                <div className="flex items-center justify-between gap-3">
                  <div>
                    <h4 className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400">Content types</h4>
                    <p className="mt-1 text-xs text-slate-500">Start here</p>
                  </div>
                  <span className="rounded-full border border-white/10 bg-white/[0.04] px-2 py-1 text-[11px] text-slate-400">{contentTypes.length}</span>
                </div>

                <div className="mt-4 space-y-2">
                  {contentTypes.map((ct) => {
                    const isActive = contentTypeId === ct.id
                    const visualKey = getContentTypeVisualKey(ct.slug)
                    const categoryCount = ct.rootCategories?.length || 0

                    return (
                      <button
                        key={ct.id}
                        type="button"
                        onClick={() => handleContentTypeChange(ct.id)}
                        className={[
                          'group flex w-full items-center gap-3 rounded-2xl border px-3 py-3 text-left transition-all',
                          isActive
                            ? 'border-emerald-400/40 bg-emerald-400/10 shadow-[0_0_0_1px_rgba(52,211,153,0.18)]'
                            : 'border-white/10 bg-white/[0.03] hover:border-white/20 hover:bg-white/[0.06]',
                        ].join(' ')}
                      >
                        <div className={`flex h-12 w-12 items-center justify-center rounded-2xl border ${isActive ? 'border-emerald-400/30 bg-emerald-400/10' : 'border-white/10 bg-white/[0.04]'}`}>
                          <img
                            src={`/gfx/mascot_${visualKey}.webp`}
                            alt=""
                            className="h-8 w-8 object-contain"
                            onError={(e) => { e.target.style.display = 'none' }}
                          />
                        </div>
                        <div className="min-w-0 flex-1">
                          <div className={`text-sm font-semibold ${isActive ? 'text-emerald-200' : 'text-white'}`}>{ct.name}</div>
                          <div className="mt-1 text-[11px] text-slate-500">{categoryCount} {categoryCount === 1 ? 'category' : 'categories'}</div>
                        </div>
                        <div className={`text-xs ${isActive ? 'text-emerald-300' : 'text-slate-500 group-hover:text-slate-300'}`}>
                          {isActive ? 'Selected' : 'Open'}
                        </div>
                      </button>
                    )
                  })}
                </div>
              </div>

              <div className="rounded-2xl border border-white/10 bg-[radial-gradient(circle_at_top_left,_rgba(14,165,233,0.08),_rgba(15,23,36,0.92)_52%)] p-4 sm:p-5">
                <div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
                  <div>
                    <h4 className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-400">Category path</h4>
                    <p className="mt-1 text-sm text-slate-400">Choose the main branch first, then refine with a subcategory when needed.</p>
                  </div>
                  <InlineAiButton onClick={() => requestAiIntent('category')} disabled={aiAction !== ''} loading={aiAction === 'analyze' || aiAction === 'regenerate'}>
                    Category
                  </InlineAiButton>
                </div>

                {!selectedCT && (
                  <div className="mt-5 rounded-2xl border border-dashed border-white/12 bg-white/[0.02] px-5 py-10 text-center">
                    <div className="text-sm font-medium text-white">Select a content type first</div>
                    <p className="mt-2 text-sm text-slate-500">Once you choose the content type, the matching category tree will appear here.</p>
                  </div>
                )}

                {selectedCT && (
                  <div className="mt-5 space-y-5">
                    <div className="flex items-center gap-2 text-sm text-slate-400">
                      <span className="rounded-full border border-emerald-400/20 bg-emerald-400/10 px-2.5 py-1 text-emerald-200">{selectedCT.name}</span>
                      <span>contains {rootCategories.length} top-level {rootCategories.length === 1 ? 'category' : 'categories'}</span>
                    </div>

                    {selectedRoot && !isCategoryChooserOpen && (
                      <div className="rounded-2xl border border-purple-400/25 bg-purple-400/[0.08] p-4">
                        <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
                          <div>
                            <div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-purple-200/80">Selected category</div>
                            <div className="mt-1 text-lg font-semibold text-white">{selectedRoot.name}</div>
                            <div className="mt-1 text-sm text-slate-400">
                              {subCategories.length > 0
                                ? `Next step: choose one of the ${subCategories.length} subcategories below.`
                                : 'This category is complete. No subcategory is required.'}
                            </div>
                          </div>
                          <button
                            type="button"
                            onClick={() => setIsCategoryChooserOpen(true)}
                            className="inline-flex items-center justify-center rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm font-medium text-slate-200 transition hover:border-white/20 hover:bg-white/[0.08] hover:text-white"
                          >
                            Change
                          </button>
                        </div>
                      </div>
                    )}

                    {(!selectedRoot || isCategoryChooserOpen) && (
                      <div className="grid gap-3 lg:grid-cols-2">
                        {rootCategories.map((cat) => {
                          const isActive = categoryId === cat.id
                          const childCount = cat.children?.length || 0

                          return (
                            <button
                              key={cat.id}
                              type="button"
                              onClick={() => handleCategoryChange(cat.id)}
                              className={[
                                'rounded-2xl border px-4 py-4 text-left transition-all',
                                isActive
                                  ? 'border-purple-400/40 bg-purple-400/12 shadow-[0_0_0_1px_rgba(192,132,252,0.15)]'
                                  : 'border-white/10 bg-white/[0.03] hover:border-white/20 hover:bg-white/[0.05]',
                              ].join(' ')}
                            >
                              <div className="flex items-start justify-between gap-3">
                                <div>
                                  <div className={`text-sm font-semibold ${isActive ? 'text-purple-200' : 'text-white'}`}>{cat.name}</div>
                                  <div className="mt-1 text-[11px] text-slate-500">{childCount > 0 ? `${childCount} subcategories available` : 'Standalone category'}</div>
                                </div>
                                <span className={`rounded-full px-2 py-1 text-[11px] ${isActive ? 'bg-purple-300/15 text-purple-200' : 'bg-white/[0.05] text-slate-500'}`}>
                                  {isActive ? 'Selected' : 'Choose'}
                                </span>
                              </div>
                            </button>
                          )
                        })}
                      </div>
                    )}

                    {selectedRoot && subCategories.length > 0 && (
                      <div className="rounded-2xl border border-cyan-400/15 bg-cyan-400/[0.05] p-4">
                        <div className="flex items-center justify-between gap-3">
                          <div>
                            <h5 className="text-[11px] font-semibold uppercase tracking-[0.18em] text-cyan-200/80">Subcategories</h5>
                            <p className="mt-1 text-sm text-slate-400">Refine <span className="text-white">{selectedRoot.name}</span> with one more level.</p>
                          </div>
                          <span className="rounded-full border border-cyan-400/20 bg-cyan-400/10 px-2 py-1 text-[11px] text-cyan-200">{subCategories.length}</span>
                        </div>

                        {!subCategoryId && (
                          <div className="mt-4 rounded-xl border border-amber-400/20 bg-amber-400/10 px-3 py-2 text-sm text-amber-100">
                            Subcategory still needs to be selected.
                          </div>
                        )}

                        <div className="mt-4 flex flex-wrap gap-2.5">
                          {subCategories.map((sub) => {
                            const isActive = subCategoryId === sub.id
                            return (
                              <button
                                key={sub.id}
                                type="button"
                                onClick={() => handleSubCategoryChange(sub.id)}
                                className={[
                                  'rounded-xl border px-3 py-2 text-xs font-medium transition-all',
                                  isActive
                                    ? 'border-cyan-400/40 bg-cyan-400/15 text-cyan-200'
                                    : 'border-white/10 bg-white/[0.04] text-slate-300 hover:border-white/20 hover:text-white',
                                ].join(' ')}
                              >
                                {sub.name}
                              </button>
                            )
                          })}
                        </div>
                      </div>
                    )}

                    {selectedRoot && subCategories.length === 0 && (
                      <div className="rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3 text-sm text-slate-400">
                        <span className="text-white font-medium">{selectedRoot.name}</span> does not have subcategories. Selecting it is enough.
                      </div>
                    )}
                  </div>
                )}

                {errors.category_id && <p className="mt-4 text-xs text-red-400">{errors.category_id[0]}</p>}
              </div>
            </div>
          </Section>

          </div>
          )}

          {/* ── Details tab ── */}
          {activeTab === 'details' && (
          <Section id="details" className="space-y-5">
            <SectionTitle icon="fa-solid fa-pen-fancy">Details</SectionTitle>

            <TextInput
              label={<FieldLabel label="Title" actionLabel="Title" onAction={() => requestAiIntent('title')} disabled={aiAction !== ''} loading={aiAction === 'analyze' || aiAction === 'regenerate'} />}
              value={title}
              onChange={handleTitleChange}
              placeholder="Give your artwork a title"
              error={errors.title?.[0]}
              required
            />

            <FormField label={<FieldLabel label="Description" actionLabel="Description" onAction={() => requestAiIntent('description')} disabled={aiAction !== ''} loading={aiAction === 'analyze' || aiAction === 'regenerate'} />} htmlFor="artwork-description">
              <RichTextEditor
                content={description}
                onChange={handleDescriptionChange}
                placeholder="Describe your artwork, tools, inspiration…"
                error={errors.description?.[0]}
                minHeight={12}
                autofocus={false}
              />
            </FormField>

            <Section className="space-y-5 border-white/8 bg-white/[0.02]">
              <div className="flex flex-wrap items-start justify-between gap-3">
                <div>
                  <SectionTitle icon="fa-solid fa-users">Attribution</SectionTitle>
                  <p className="-mt-2 text-sm text-slate-400">Switch between personal and group context, then maintain primary author and contributor credits without leaving the edit screen.</p>
                </div>
                <span className={`rounded-full border px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.16em] ${groupSlug ? 'border-sky-300/20 bg-sky-300/10 text-sky-100' : 'border-white/10 bg-white/[0.04] text-slate-300'}`}>
                  {selectedGroupOption ? `Group: ${selectedGroupOption.name}` : 'Personal publish'}
                </span>
              </div>

              <NovaSelect
                label="Publishing identity"
                value={groupSlug || ''}
                onChange={(nextValue) => setGroupSlug(String(nextValue || ''))}
                options={publishingIdentityOptions}
                searchable={false}
                placeholder="Choose publishing identity"
                error={errors.group?.[0]}
                hint={selectedGroupOption
                  ? 'The artwork will be publicly published under the selected group while authorship stays editable below.'
                  : 'Personal publishing keeps the artwork under your own creator profile.'}
                className="mt-2 bg-black/20"
                renderOption={(option) => (
                  <span className="flex min-w-0 items-center gap-3">
                    <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-full border border-white/10 bg-white/[0.04]">
                      {option.icon}
                    </span>
                    <span className="min-w-0">
                      <span className="block truncate font-medium text-white">{option.label}</span>
                      <span className="block truncate text-[11px] text-slate-500">{option.contextLabel}</span>
                    </span>
                  </span>
                )}
              />

              {groupSlug ? (
                <div className="grid gap-5 lg:grid-cols-[minmax(0,0.95fr)_minmax(0,1.05fr)]">
                  <div>
                    <NovaSelect
                      label="Primary author"
                      value={primaryAuthorUserId || null}
                      onChange={(nextValue) => setPrimaryAuthorUserId(nextValue ? Number(nextValue) : null)}
                      options={primaryAuthorOptions}
                      placeholder="Choose primary author"
                      searchable={primaryAuthorOptions.length > 6}
                      error={errors.primary_author_user_id?.[0]}
                      hint="Primary author remains the lead creator shown on the public artwork page."
                      className="mt-2 bg-black/20"
                      renderOption={(option) => (
                        <span className="flex min-w-0 items-center gap-3">
                          {option.avatarUrl ? (
                            <img src={option.avatarUrl} alt="" className="h-7 w-7 shrink-0 rounded-full object-cover" />
                          ) : (
                            <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-full border border-white/10 bg-white/[0.04] text-slate-400">
                              <i className="fa-solid fa-user text-[11px]" aria-hidden="true" />
                            </span>
                          )}
                          <span className="min-w-0">
                            <span className="block truncate font-medium text-white">{option.label}</span>
                            {option.username ? <span className="block truncate text-[11px] text-slate-500">@{option.username}</span> : null}
                          </span>
                        </span>
                      )}
                    />
                  </div>

                  <div>
                    <div className="flex items-center justify-between gap-3">
                      <span className="text-sm font-medium text-white/90">Contributors</span>
                      <span className="text-xs text-slate-500">Optional</span>
                    </div>
                    <div className="mt-2 grid gap-2">
                      {currentContributorOptions.filter((user) => Number(user.id) !== Number(primaryAuthorUserId)).map((user) => {
                        const active = contributorUserIds.some((id) => Number(id) === Number(user.id))
                        const creditMeta = contributorCredits?.[user.id] || contributorCredits?.[String(user.id)] || { creditRole: '', isPrimary: false }

                        return (
                          <div
                            key={user.id}
                            className={[
                              'rounded-2xl border px-3 py-3 transition',
                              active
                                ? 'border-sky-300/30 bg-sky-300/10 text-white'
                                : 'border-white/10 bg-white/[0.03] text-slate-200 hover:border-white/20 hover:bg-white/[0.06]',
                            ].join(' ')}
                          >
                            <div className="flex items-center gap-3">
                              {user.avatar_url ? <img src={user.avatar_url} alt={user.name || user.username} className="h-10 w-10 rounded-2xl object-cover" /> : <div className="flex h-10 w-10 items-center justify-center rounded-2xl border border-white/10 bg-white/[0.03] text-slate-400"><i className="fa-solid fa-user" /></div>}
                              <div className="min-w-0 flex-1">
                                <div className="truncate text-sm font-semibold">{user.name || user.username}</div>
                                <div className="truncate text-xs text-slate-400">@{user.username}</div>
                              </div>
                              <button
                                type="button"
                                onClick={() => {
                                  setContributorUserIds((current) => {
                                    const nextIds = new Set(current.map((id) => Number(id)).filter((id) => id !== Number(primaryAuthorUserId)))
                                    if (nextIds.has(Number(user.id))) {
                                      nextIds.delete(Number(user.id))
                                    } else {
                                      nextIds.add(Number(user.id))
                                    }

                                    const normalizedIds = Array.from(nextIds)
                                    setContributorCredits((currentCredits) => normalizeContributorCredits(normalizedIds, currentCredits))
                                    return normalizedIds
                                  })
                                }}
                                className={[
                                  'inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-xs font-semibold transition',
                                  active
                                    ? 'border-sky-300/40 bg-sky-300/20 text-sky-50'
                                    : 'border-white/10 bg-white/[0.03] text-white/70 hover:border-white/20 hover:text-white',
                                ].join(' ')}
                              >
                                <span className={['inline-flex h-4 w-4 items-center justify-center rounded-full border text-[10px]', active ? 'border-sky-300/40 bg-sky-300/20 text-sky-50' : 'border-white/10 bg-white/[0.03] text-white/35'].join(' ')}>{active ? '✓' : ''}</span>
                                {active ? 'Added' : 'Add credit'}
                              </button>
                            </div>

                            {active ? (
                              <div className="mt-4 grid gap-3 md:grid-cols-[minmax(0,1fr)_auto] md:items-end">
                                <label className="block">
                                  <span className="text-xs font-medium uppercase tracking-[0.16em] text-slate-300">Credit role</span>
                                  <input
                                    type="text"
                                    value={creditMeta.creditRole || ''}
                                    onChange={(event) => setContributorCredits((current) => ({
                                      ...normalizeContributorCredits(contributorUserIds, current),
                                      [Number(user.id)]: {
                                        ...(normalizeContributorCredits(contributorUserIds, current)[Number(user.id)] || { isPrimary: false }),
                                        creditRole: event.target.value,
                                      },
                                    }))}
                                    placeholder="Colorist, concept support, layout..."
                                    className="mt-2 w-full rounded-xl border border-white/15 bg-black/20 px-3 py-3 text-sm text-white outline-none transition focus:border-sky-300/40"
                                  />
                                </label>
                                <button
                                  type="button"
                                  onClick={() => setContributorCredits((current) => {
                                    const nextCredits = normalizeContributorCredits(contributorUserIds, current)
                                    contributorUserIds.forEach((id) => {
                                      nextCredits[id] = {
                                        ...(nextCredits[id] || { creditRole: '' }),
                                        isPrimary: id === Number(user.id),
                                      }
                                    })
                                    return nextCredits
                                  })}
                                  className={[
                                    'inline-flex items-center justify-center rounded-xl border px-3 py-3 text-sm font-medium transition',
                                    creditMeta.isPrimary
                                      ? 'border-emerald-300/35 bg-emerald-400/12 text-emerald-100'
                                      : 'border-white/10 bg-white/[0.03] text-slate-200 hover:border-white/20 hover:bg-white/[0.06] hover:text-white',
                                  ].join(' ')}
                                >
                                  {creditMeta.isPrimary ? 'Lead support' : 'Set lead support'}
                                </button>
                              </div>
                            ) : null}
                          </div>
                        )
                      })}
                    </div>
                    {errors.contributor_credits?.[0] ? <p className="mt-2 text-xs text-red-400">{errors.contributor_credits[0]}</p> : null}
                  </div>
                </div>
              ) : (
                <div className="rounded-2xl border border-white/10 bg-white/[0.03] px-4 py-3 text-sm text-slate-400">
                  Personal publishing uses your own creator profile as the primary author automatically.
                </div>
              )}
            </Section>
          </Section>
          )}

          {/* ── Evolution tab ── */}
          {activeTab === 'evolution' && (
          <Section id="evolution" className="space-y-6">
            <div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
              <div>
                <SectionTitle icon="fa-solid fa-code-branch">Artwork Evolution</SectionTitle>
                <p className="-mt-2 text-sm text-slate-400">Connect this piece to an older public original so the artwork page can tell a clear Then & Now story in both directions.</p>
              </div>
              <div className={`inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-[11px] font-semibold uppercase tracking-[0.16em] ${evolutionTarget ? 'border-sky-300/25 bg-sky-300/10 text-sky-100' : 'border-white/10 bg-white/[0.04] text-slate-300'}`}>
                <i className="fa-solid fa-sparkles text-[10px]" aria-hidden="true" />
                {evolutionTarget ? (selectedEvolutionType?.short_label || 'Linked') : 'No original linked'}
              </div>
            </div>

            <div className="grid gap-6 xl:grid-cols-[minmax(0,1.2fr)_minmax(320px,0.8fr)]">
              <div className="space-y-4">
                <ArtworkEvolutionSearchPicker
                  artworkId={artwork?.id}
                  selected={evolutionTarget}
                  onSelect={(option) => setEvolutionTarget(option)}
                  disabled={saving}
                />
                {errors.evolution_target_artwork_id?.[0] ? <p className="text-sm text-red-400">{errors.evolution_target_artwork_id[0]}</p> : null}
              </div>

              <div className="space-y-4">
                <RightRailCard title="Relation settings">
                  <div className="space-y-4">
                    <label className="block">
                      <span className="text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Story type</span>
                      <select
                        value={evolutionRelationType}
                        onChange={(event) => setEvolutionRelationType(event.target.value)}
                        disabled={saving || !evolutionTarget}
                        className="mt-2 w-full rounded-2xl border border-white/10 bg-[#0d1726] px-4 py-3 text-sm text-white outline-none transition focus:border-sky-300/35 disabled:cursor-not-allowed disabled:opacity-60"
                      >
                        {evolutionRelationTypes.map((option) => (
                          <option key={option.value} value={option.value}>
                            {option.label}
                          </option>
                        ))}
                      </select>
                    </label>
                    {errors.evolution_relation_type?.[0] ? <p className="text-sm text-red-400">{errors.evolution_relation_type[0]}</p> : null}

                    <label className="block">
                      <span className="text-xs font-semibold uppercase tracking-[0.18em] text-slate-400">Creator note</span>
                      <textarea
                        value={evolutionNote}
                        onChange={(event) => setEvolutionNote(event.target.value)}
                        placeholder="Optional context for viewers: what changed, what you learned, why this version matters..."
                        disabled={saving || !evolutionTarget}
                        rows={6}
                        className="mt-2 w-full rounded-[24px] border border-white/10 bg-[#0d1726] px-4 py-3 text-sm leading-6 text-white outline-none transition focus:border-sky-300/35 disabled:cursor-not-allowed disabled:opacity-60"
                      />
                    </label>
                    {errors.evolution_note?.[0] ? <p className="text-sm text-red-400">{errors.evolution_note[0]}</p> : null}
                  </div>
                </RightRailCard>

                <RightRailCard title="Public behavior">
                  <div className="space-y-3 text-sm leading-relaxed text-slate-300">
                    <p>The newer artwork gets the main comparison panel. The older artwork gets an updated-version card pointing back here.</p>
                    <p>Only published public artworks can be linked, and the original has to be older than the piece you are editing.</p>
                    <p>{evolutionTarget ? `Current target: ${evolutionTarget.title}` : 'Pick an older artwork first to unlock relation type and note settings.'}</p>
                  </div>
                </RightRailCard>
              </div>
            </div>
          </Section>
          )}

          {/* ── AI Assist tab ── */}
          {activeTab === 'ai' && (
          <Section id="ai-assist" className="space-y-5">
            <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
              <div>
                <SectionTitle icon="fa-solid fa-wand-magic-sparkles">AI Assist</SectionTitle>
                <p className="text-sm text-slate-400">Review-only suggestions built from the current artwork image. Nothing is written to the artwork until you apply it.</p>
              </div>
              <div className="flex items-center gap-3 self-start">
                <div className={`inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-xs font-semibold ${statusTone(aiStatus)}`}>
                  <span className={`h-2 w-2 rounded-full ${aiStatus === 'ready' ? 'bg-emerald-300' : aiStatus === 'failed' ? 'bg-red-300' : aiStatus === 'queued' || aiStatus === 'processing' ? 'bg-sky-300' : 'bg-slate-400'}`} />
                  <span>{statusLabel(aiStatus)}</span>
                </div>
                <button
                  type="button"
                  onClick={toggleAiPanel}
                  className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-3 py-1.5 text-xs font-semibold text-slate-300 transition hover:bg-white/[0.08] hover:text-white"
                >
                  <span>{isAiPanelOpen ? 'Collapse' : 'Expand'}</span>
                </button>
              </div>
            </div>

            {isAiPanelOpen && (
              <>
                <div className="flex flex-wrap gap-2">
                  <Button variant="secondary" size="xs" onClick={() => requestAiIntent('analyze', 'analyze')} loading={aiAction === 'analyze'}>
                    {aiDirect ? 'Analyze now' : 'Analyze artwork'}
                  </Button>
                  <Button variant="secondary" size="xs" onClick={handleImproveAll}>
                    Improve all
                  </Button>
                  <Button variant="ghost" size="xs" onClick={() => requestAiIntent('title')}>
                    Generate title
                  </Button>
                  <Button variant="ghost" size="xs" onClick={() => requestAiIntent('description')}>
                    Generate description
                  </Button>
                  <Button variant="ghost" size="xs" onClick={() => requestAiIntent('tags')}>
                    Suggest tags
                  </Button>
                  <Button variant="ghost" size="xs" onClick={() => requestAiIntent('category')}>
                    Suggest category
                  </Button>
                  <Button variant="ghost" size="xs" onClick={() => requestAiIntent('similar')}>
                    Find similar
                  </Button>
                  <Button variant="ghost" size="xs" onClick={() => requestAiIntent('analyze', 'regenerate')} loading={aiAction === 'regenerate'}>
                    Refresh suggestions
                  </Button>
                  <Button variant="ghost" size="xs" onClick={() => setIsAiDebugOpen((current) => !current)}>
                    {isAiDebugOpen ? 'Hide debug' : 'Show debug'}
                  </Button>
                </div>

                <div className="rounded-xl border border-white/10 bg-white/[0.03] px-4 py-3">
                  <Toggle
                    checked={aiDirect}
                    onChange={(event) => setAiDirect(event.target.checked)}
                    label="Run AI directly"
                    hint="Optional. When enabled, AI analysis runs inline and returns suggestions immediately instead of going through the queue."
                    size="sm"
                    variant="sky"
                    disabled={aiAction !== ''}
                  />
                </div>

                {aiLoading && (
                  <div className="flex items-center gap-3 rounded-xl border border-white/10 bg-white/[0.03] px-4 py-3 text-sm text-slate-300">
                    <div className="h-4 w-4 rounded-full border-2 border-sky-400/20 border-t-sky-300 animate-spin" />
                    <span>Loading AI assist data…</span>
                  </div>
                )}

                {aiData?.error_message && (
                  <div className="rounded-xl border border-red-400/20 bg-red-400/10 px-4 py-3 text-sm text-red-100">
                    {aiData.error_message}
                  </div>
                )}

                {isAiDebugOpen && (
                  <div className="rounded-2xl border border-amber-400/20 bg-amber-400/[0.06] p-4 space-y-3">
                    <div className="flex items-center justify-between gap-3">
                      <div>
                        <h4 className="text-sm font-semibold text-white">AI debug</h4>
                        <p className="mt-1 text-xs text-slate-400">Inspect the editor request, the outbound vision POST payload, and the raw analysis returned to the suggestion builder.</p>
                      </div>
                      <button type="button" onClick={() => copyText(JSON.stringify(aiDebugPayload, null, 2))} className="text-xs text-slate-300 transition hover:text-white">Copy JSON</button>
                    </div>

                    <div className="grid gap-3 xl:grid-cols-2">
                      <div className="rounded-xl border border-white/10 bg-black/20 p-3">
                        <div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">Editor request</div>
                        <pre className="mt-3 overflow-x-auto text-xs leading-6 text-slate-300 whitespace-pre-wrap">{JSON.stringify(lastAiRequest, null, 2)}</pre>
                      </div>
                      <div className="rounded-xl border border-white/10 bg-black/20 p-3">
                        <div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">Vision request + response</div>
                        <pre className="mt-3 overflow-x-auto text-xs leading-6 text-slate-300 whitespace-pre-wrap">{JSON.stringify(aiData?.debug?.vision_debug || null, null, 2)}</pre>
                      </div>
                    </div>

                    <div className="rounded-xl border border-white/10 bg-black/20 p-3">
                      <div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">Raw analysis used for suggestions</div>
                      <pre className="mt-3 overflow-x-auto text-xs leading-6 text-slate-300 whitespace-pre-wrap">{JSON.stringify(aiData?.debug?.analysis || null, null, 2)}</pre>
                    </div>
                  </div>
                )}

                <div className="grid gap-4 xl:grid-cols-2">
              <div className="rounded-2xl border border-white/10 bg-white/[0.03] p-4 space-y-3">
                <div className="flex items-center justify-between gap-3">
                  <h4 className="text-sm font-semibold text-white">Title suggestions</h4>
                  <button type="button" onClick={() => requestAiIntent('title', 'regenerate')} className="text-xs text-slate-400 transition hover:text-white">Regenerate</button>
                </div>
                {(aiData?.title_suggestions || []).length === 0 && <p className="text-sm text-slate-500">Analyze the artwork to generate title ideas.</p>}
                {(aiData?.title_suggestions || []).map((item) => (
                  <div key={item.text} className="rounded-xl border border-white/10 bg-white/[0.04] p-3">
                    <div className="flex items-start justify-between gap-3">
                      <div>
                        <div className="text-sm font-medium text-white">{item.text}</div>
                        {typeof item.confidence === 'number' && <div className="text-[11px] text-slate-500">Confidence {Math.round(item.confidence * 100)}%</div>}
                      </div>
                      <div className="flex flex-wrap justify-end gap-2">
                        <button type="button" onClick={() => applyTitleSuggestion(item.text, 'replace')} className="text-xs text-sky-200 transition hover:text-white">Replace</button>
                        <button type="button" onClick={() => applyTitleSuggestion(item.text, 'insert')} className="text-xs text-slate-300 transition hover:text-white">Insert</button>
                        <button type="button" onClick={() => copyText(item.text)} className="text-xs text-slate-400 transition hover:text-white">Copy</button>
                      </div>
                    </div>
                  </div>
                ))}
              </div>

              <div className="rounded-2xl border border-white/10 bg-white/[0.03] p-4 space-y-3">
                <div className="flex items-center justify-between gap-3">
                  <h4 className="text-sm font-semibold text-white">Description suggestions</h4>
                  <button type="button" onClick={() => requestAiIntent('description', 'regenerate')} className="text-xs text-slate-400 transition hover:text-white">Regenerate</button>
                </div>
                {(aiData?.description_suggestions || []).length === 0 && <p className="text-sm text-slate-500">AI descriptions appear here after analysis.</p>}
                {(aiData?.description_suggestions || []).map((item) => (
                  <div key={`${item.variant}-${item.text}`} className="rounded-xl border border-white/10 bg-white/[0.04] p-3 space-y-2">
                    <div className="flex items-center justify-between gap-3">
                      <div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">{item.variant}</div>
                      {typeof item.confidence === 'number' && <div className="text-[11px] text-slate-500">{Math.round(item.confidence * 100)}%</div>}
                    </div>
                    <p className="text-sm leading-6 text-slate-200">{item.text}</p>
                    <div className="flex flex-wrap gap-2">
                      <button type="button" onClick={() => applyDescriptionSuggestion(item.text, 'replace')} className="text-xs text-sky-200 transition hover:text-white">Replace</button>
                      <button type="button" onClick={() => applyDescriptionSuggestion(item.text, 'append')} className="text-xs text-slate-300 transition hover:text-white">Append</button>
                      <button type="button" onClick={() => copyText(item.text)} className="text-xs text-slate-400 transition hover:text-white">Copy</button>
                    </div>
                  </div>
                ))}
              </div>

              <div className="rounded-2xl border border-white/10 bg-white/[0.03] p-4 space-y-3">
                <div className="flex items-center justify-between gap-3">
                  <h4 className="text-sm font-semibold text-white">Tag suggestions</h4>
                  <button type="button" onClick={() => requestAiIntent('tags', 'regenerate')} className="text-xs text-slate-400 transition hover:text-white">Regenerate</button>
                </div>
                {(aiData?.tag_suggestions || []).length === 0 && <p className="text-sm text-slate-500">Suggested tags, confidence, and quick-apply actions appear here.</p>}
                {(aiData?.tag_suggestions || []).length > 0 && (
                  <>
                    <div className="flex flex-wrap gap-2">
                      {(aiData?.tag_suggestions || []).map((item) => {
                        const isApplied = tagSlugs.includes(item.tag)
                        const isSelected = selectedAiTags.includes(item.tag)
                        return (
                          <button
                            key={item.tag}
                            type="button"
                            onClick={() => toggleSuggestedTag(item.tag)}
                            className={`rounded-full border px-3 py-1 text-xs font-semibold transition ${isSelected ? 'border-emerald-400/30 bg-emerald-400/10 text-emerald-200' : isApplied ? 'border-white/20 bg-white/[0.08] text-white' : 'border-sky-400/20 bg-sky-400/10 text-sky-200 hover:bg-sky-400/15'}`}
                          >
                            {isSelected ? '✓' : isApplied ? '•' : '+'} {item.tag}
                            {typeof item.confidence === 'number' && <span className="ml-1 text-[10px] text-white/60">{Math.round(item.confidence * 100)}%</span>}
                          </button>
                        )
                      })}
                    </div>
                    <div className="flex flex-wrap gap-2">
                      <button type="button" onClick={() => applyTagSuggestions(selectedAiTags, 'add')} className="text-xs text-sky-200 transition hover:text-white">Add selected</button>
                      <button type="button" onClick={() => applyTagSuggestions(aiSuggestedTags, 'add')} className="text-xs text-slate-300 transition hover:text-white">Add all</button>
                      <button type="button" onClick={() => applyTagSuggestions(aiSuggestedTags, 'remove')} className="text-xs text-slate-400 transition hover:text-white">Remove suggested</button>
                    </div>
                  </>
                )}
              </div>

              <div className="rounded-2xl border border-white/10 bg-white/[0.03] p-4 space-y-3">
                <div className="flex items-center justify-between gap-3">
                  <h4 className="text-sm font-semibold text-white">Category suggestions</h4>
                  <button type="button" onClick={() => requestAiIntent('category', 'regenerate')} className="text-xs text-slate-400 transition hover:text-white">Regenerate</button>
                </div>
                {!aiData?.content_type && !aiData?.category && <p className="text-sm text-slate-500">AI content-type and category candidates appear here after analysis.</p>}
                {aiData?.content_type && (
                  <div className="rounded-xl border border-white/10 bg-white/[0.04] p-3">
                    <div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">Suggested content type</div>
                    <div className="mt-1 text-sm font-medium text-white">{aiData.content_type.label}</div>
                    <div className="mt-2">
                      <button type="button" onClick={() => applyCategorySuggestion(aiData.category || { content_type_id: aiData.content_type.id }, 'content_type')} className="text-xs text-sky-200 transition hover:text-white">Apply content type</button>
                    </div>
                  </div>
                )}
                {aiData?.category && (
                  <div className="rounded-xl border border-white/10 bg-white/[0.04] p-3 space-y-3">
                    <div>
                      <div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">Suggested category</div>
                      <div className="mt-1 text-sm font-medium text-white">{aiData.category.label}</div>
                    </div>
                    <div className="flex flex-wrap gap-2">
                      <button type="button" onClick={() => applyCategorySuggestion(aiData.category, 'category')} className="text-xs text-sky-200 transition hover:text-white">Apply category</button>
                      <button type="button" onClick={() => applyCategorySuggestion(aiData.category, 'both')} className="text-xs text-slate-300 transition hover:text-white">Apply both</button>
                    </div>
                    {(aiData.category.alternatives || []).length > 0 && (
                      <div className="flex flex-wrap gap-2">
                        {aiData.category.alternatives.map((item) => (
                          <button key={item.id} type="button" onClick={() => applyCategorySuggestion(item, 'both')} className="rounded-full border border-white/10 bg-white/[0.03] px-3 py-1 text-xs text-slate-300 transition hover:text-white">
                            {item.label}
                          </button>
                        ))}
                      </div>
                    )}
                  </div>
                )}
              </div>
            </div>

            <div className="rounded-2xl border border-white/10 bg-white/[0.03] p-4 space-y-3">
              <div className="flex items-center justify-between gap-3">
                <h4 className="text-sm font-semibold text-white">Similar / duplicate candidates</h4>
                <button type="button" onClick={() => requestAiIntent('similar', 'regenerate')} className="text-xs text-slate-400 transition hover:text-white">Refresh</button>
              </div>
              {(aiData?.similar_candidates || []).length === 0 && <p className="text-sm text-slate-500">Possible duplicates or visually similar artworks will appear here.</p>}
              <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
                {(aiData?.similar_candidates || []).map((item) => (
                  <div key={item.artwork_id} className="rounded-xl border border-white/10 bg-white/[0.04] p-3">
                    <div className="aspect-[4/3] overflow-hidden rounded-lg bg-white/5">
                      {item.thumbnail_url ? (
                        <img src={item.thumbnail_url} alt={item.title || 'Similar artwork'} className="h-full w-full object-cover" />
                      ) : (
                        <div className="flex h-full items-center justify-center text-xs text-slate-500">No preview</div>
                      )}
                    </div>
                    <div className="mt-3 space-y-1">
                      <div className="text-sm font-medium text-white">{item.title || `Artwork #${item.artwork_id}`}</div>
                      <div className="text-[11px] text-slate-500">#{item.artwork_id} · {item.match_type} · {typeof item.score === 'number' ? `${Math.round(item.score * 100)}%` : 'n/a'}</div>
                      {item.owner && <div className="text-[11px] text-slate-500">{item.owner}</div>}
                      {item.review_state && <div className="text-[11px] text-emerald-300 uppercase tracking-[0.18em]">{item.review_state}</div>}
                    </div>
                    <div className="mt-3 flex flex-wrap gap-2">
                      {item.url && <a href={item.url} target="_blank" rel="noreferrer" onClick={() => trackAiEvent('duplicate_candidate_viewed', { candidate_artwork_id: item.artwork_id, match_type: item.match_type })} className="text-xs text-sky-200 transition hover:text-white">Open</a>}
                      <button type="button" onClick={() => persistAiAction({ similar_actions: [{ artwork_id: item.artwork_id, state: 'ignored' }] })} className="text-xs text-slate-300 transition hover:text-white">Ignore</button>
                      <button type="button" onClick={() => persistAiAction({ similar_actions: [{ artwork_id: item.artwork_id, state: 'reviewed' }] })} className="text-xs text-slate-400 transition hover:text-white">Mark as reviewed</button>
                    </div>
                  </div>
                ))}
              </div>
            </div>
              </>
            )}
          </Section>
          )}

          {/* ── Tags tab ── */}
          {activeTab === 'tags' && (
          <Section id="tags" className="space-y-4">
            <div className="flex items-center justify-between gap-3">
              <SectionTitle icon="fa-solid fa-tags">Tags</SectionTitle>
              <InlineAiButton onClick={() => requestAiIntent('tags')} disabled={aiAction !== ''} loading={aiAction === 'analyze' || aiAction === 'regenerate'}>
                Tags
              </InlineAiButton>
            </div>
            <TagPicker
              value={tagSlugs}
              onChange={handleTagChange}
              suggestedTags={aiSuggestedTags}
              maxTags={30}
              searchEndpoint="/api/studio/tags/search"
              popularEndpoint="/api/studio/tags/search"
              error={errors.tags?.[0]}
            />
          </Section>
          )}

          {/* ── Visibility tab ── */}
          {activeTab === 'visibility' && (
          <Section id="visibility" className="space-y-5">
            <div className="space-y-1">
                <SectionTitle icon="fa-solid fa-eye">Visibility</SectionTitle>
              <p className="text-xs text-slate-500 -mt-2">
                Match the same publish options used during upload, including unlisted access and scheduled publishing.
              </p>
            </div>

            <div className="grid gap-2">
              {[
                { value: 'public', label: 'Public', hint: 'Visible to everyone' },
                { value: 'unlisted', label: 'Unlisted', hint: 'Available by direct link' },
                { value: 'private', label: 'Private', hint: 'Keep as draft visibility' },
              ].map((option) => {
                const active = visibility === option.value
                return (
                  <button
                    key={option.value}
                    type="button"
                    onClick={() => setVisibility(option.value)}
                    className={[
                      'flex items-start justify-between gap-3 rounded-2xl border px-4 py-4 text-left transition',
                      active
                        ? 'border-sky-300/30 bg-sky-400/10 text-white'
                        : 'border-white/10 bg-white/[0.03] text-white/75 hover:border-white/20 hover:bg-white/[0.06]',
                    ].join(' ')}
                  >
                    <div>
                      <div className="text-sm font-semibold">{option.label}</div>
                      <div className="mt-1 text-xs text-white/50">{option.hint}</div>
                    </div>
                    <span className={[
                      'mt-0.5 inline-flex h-5 w-5 items-center justify-center rounded-full border text-[10px]',
                      active ? 'border-sky-300/40 bg-sky-400/20 text-sky-100' : 'border-white/10 bg-white/5 text-white/35',
                    ].join(' ')}>
                      {active ? '✓' : ''}
                    </span>
                  </button>
                )
              })}
            </div>

            <div className="rounded-2xl border border-white/10 bg-white/[0.03] p-4">
              <SchedulePublishPicker
                mode={publishMode}
                scheduledAt={scheduledAt}
                timezone={userTimezone}
                onModeChange={setPublishMode}
                onScheduleAt={setScheduledAt}
                disabled={saving}
              />
              {errors.publish_at?.[0] && (
                <p className="mt-2 text-xs text-red-400">{errors.publish_at[0]}</p>
              )}
              {errors.visibility?.[0] && (
                <p className="mt-2 text-xs text-red-400">{errors.visibility[0]}</p>
              )}
              <p className="mt-3 text-xs text-slate-500">
                {publishMode === 'schedule'
                  ? 'Scheduled artworks stay hidden until the selected time.'
                  : visibility === 'private'
                    ? 'Private keeps the artwork hidden from public views.'
                    : visibility === 'unlisted'
                      ? 'Unlisted keeps the artwork accessible but not broadly surfaced.'
                      : 'Public makes the artwork visible immediately.'}
              </p>
              </div>
          </Section>
          )}

        </div>


      </div>

      {/* ── Version History Modal ── */}
      <Modal
        open={showHistory}
        onClose={() => setShowHistory(false)}
        title="Version History"
        size="lg"
        footer={
          <p className="text-xs text-slate-500 mr-auto">
            Restoring creates a new version — nothing is deleted.
          </p>
        }
      >
        {historyLoading && (
          <div className="flex items-center justify-center py-12">
            <div className="w-6 h-6 border-2 border-accent/30 border-t-accent rounded-full animate-spin" />
          </div>
        )}

        {!historyLoading && historyData && (
          <div className="space-y-3">
            {historyData.versions.map((v) => (
              <div
                key={v.id}
                className={[
                  'rounded-xl border p-4 transition-all',
                  v.is_current
                    ? 'border-accent/40 bg-accent/10'
                    : 'border-white/10 bg-white/[0.03] hover:bg-white/[0.06]',
                ].join(' ')}
              >
                <div className="flex items-start justify-between gap-3">
                  <div className="flex-1 min-w-0">
                    <div className="flex items-center gap-2 mb-1">
                      <span className="text-xs font-bold text-white">v{v.version_number}</span>
                      {v.is_current && (
                        <span className="text-[10px] font-semibold px-1.5 py-0.5 rounded-full bg-accent/20 text-accent border border-accent/30">
                          Current
                        </span>
                      )}
                    </div>
                    <p className="text-[11px] text-slate-400">
                      {v.created_at ? new Date(v.created_at).toLocaleString() : ''}
                    </p>
                    {v.width && (
                      <p className="text-[11px] text-slate-400">
                        {v.width} &times; {v.height} px &middot; {formatBytes(v.file_size)}
                      </p>
                    )}
                    {v.change_note && (
                      <p className="text-xs text-slate-300 mt-1 italic">&ldquo;{v.change_note}&rdquo;</p>
                    )}
                  </div>
                  {!v.is_current && (
                    <Button
                      variant="ghost"
                      size="xs"
                      loading={restoring === v.id}
                      onClick={() => handleRestoreVersion(v.id)}
                    >
                      Restore
                    </Button>
                  )}
                </div>
              </div>
            ))}

            {historyData.versions.length === 0 && (
              <p className="text-sm text-slate-500 text-center py-8">No version history yet.</p>
            )}
          </div>
        )}
      </Modal>
    </StudioLayout>
  )
}
