// @ts-nocheck
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { EditorContent, Extension, useEditor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import CodeBlockLowlight from '@tiptap/extension-code-block-lowlight';
import Image from '@tiptap/extension-image';
import Link from '@tiptap/extension-link';
import Placeholder from '@tiptap/extension-placeholder';
import Underline from '@tiptap/extension-underline';
import Suggestion from '@tiptap/suggestion';
import { Node, mergeAttributes } from '@tiptap/core';
import { common, createLowlight } from 'lowlight';
import tippy from 'tippy.js';
import { buildBotFingerprint } from '../../lib/security/botFingerprint';
import TurnstileField from '../security/TurnstileField';
import Select from '../ui/Select';

type StoryType = {
  slug: string;
  name: string;
};

type Artwork = {
  id: number;
  title: string;
  url: string;
  thumb: string | null;
  thumbs?: {
    xs?: string | null;
    sm?: string | null;
    md?: string | null;
    lg?: string | null;
    xl?: string | null;
  };
};

type StoryPayload = {
  id?: number;
  title: string;
  excerpt: string;
  cover_image: string;
  story_type: string;
  tags_csv: string;
  meta_title: string;
  meta_description: string;
  canonical_url: string;
  og_image: string;
  status: string;
  scheduled_for: string;
  content: Record<string, unknown>;
};

type Endpoints = {
  create: string;
  update: string;
  autosave: string;
  uploadImage: string;
  artworks: string;
  previewBase: string;
  analyticsBase: string;
};

type Props = {
  mode: 'create' | 'edit';
  initialStory: StoryPayload;
  storyTypes: StoryType[];
  endpoints: Endpoints;
  csrfToken: string;
};

const EMPTY_DOC = {
  type: 'doc',
  content: [{ type: 'paragraph' }],
};

const lowlight = createLowlight(common);

const CODE_BLOCK_LANGUAGES = [
  { value: 'bash', label: 'Bash / Shell' },
  { value: 'plaintext', label: 'Plain text' },
  { value: 'php', label: 'PHP' },
  { value: 'javascript', label: 'JavaScript' },
  { value: 'typescript', label: 'TypeScript' },
  { value: 'json', label: 'JSON' },
  { value: 'html', label: 'HTML' },
  { value: 'css', label: 'CSS' },
  { value: 'sql', label: 'SQL' },
  { value: 'xml', label: 'XML / SVG' },
  { value: 'yaml', label: 'YAML' },
  { value: 'markdown', label: 'Markdown' },
];

const ArtworkBlock = Node.create({
  name: 'artworkEmbed',
  group: 'block',
  atom: true,

  addAttributes() {
    return {
      artworkId: { default: null },
      title: { default: '' },
      url: { default: '' },
      thumb: { default: '' },
    };
  },

  parseHTML() {
    return [{ tag: 'figure[data-artwork-embed]' }];
  },

  renderHTML({ HTMLAttributes }) {
    return [
      'figure',
      mergeAttributes(HTMLAttributes, {
        'data-artwork-embed': 'true',
        class: 'my-4 overflow-hidden rounded-xl border border-gray-700 bg-gray-800/70',
      }),
      [
        'a',
        {
          href: HTMLAttributes.url || '#',
          class: 'block',
          rel: 'noopener noreferrer nofollow',
          target: '_blank',
        },
        [
          'img',
          {
            src: HTMLAttributes.thumb || '',
            alt: HTMLAttributes.title || 'Artwork',
            class: 'h-48 w-full object-cover',
            loading: 'lazy',
          },
        ],
        [
          'figcaption',
          { class: 'p-3 text-sm text-gray-200' },
          `${HTMLAttributes.title || 'Artwork'} (#${HTMLAttributes.artworkId || 'n/a'})`,
        ],
      ],
    ];
  },
});

const GalleryBlock = Node.create({
  name: 'galleryBlock',
  group: 'block',
  atom: true,

  addAttributes() {
    return {
      images: { default: [] },
    };
  },

  parseHTML() {
    return [{ tag: 'div[data-gallery-block]' }];
  },

  renderHTML({ HTMLAttributes }) {
    const images = Array.isArray(HTMLAttributes.images) ? HTMLAttributes.images : [];
    const children: Array<unknown> = images.slice(0, 6).map((src: string) => [
      'img',
      { src, class: 'h-36 w-full rounded-lg object-cover', loading: 'lazy', alt: 'Gallery image' },
    ]);

    if (children.length === 0) {
      children.push(['div', { class: 'rounded-lg border border-dashed border-gray-600 p-4 text-xs text-gray-400' }, 'Empty gallery block']);
    }

    return [
      'div',
      mergeAttributes(HTMLAttributes, {
        'data-gallery-block': 'true',
        class: 'my-4 grid grid-cols-2 gap-3 rounded-xl border border-gray-700 bg-gray-800/50 p-3',
      }),
      ...children,
    ];
  },
});

const VideoEmbedBlock = Node.create({
  name: 'videoEmbed',
  group: 'block',
  atom: true,

  addAttributes() {
    return {
      src: { default: '' },
      title: { default: 'Embedded video' },
    };
  },

  parseHTML() {
    return [{ tag: 'figure[data-video-embed]' }];
  },

  renderHTML({ HTMLAttributes }) {
    return [
      'figure',
      mergeAttributes(HTMLAttributes, {
        'data-video-embed': 'true',
        class: 'my-4 overflow-hidden rounded-xl border border-gray-700 bg-gray-800/60',
      }),
      [
        'iframe',
        {
          src: HTMLAttributes.src || '',
          title: HTMLAttributes.title || 'Embedded video',
          class: 'aspect-video w-full',
          allow: 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share',
          allowfullscreen: 'true',
          frameborder: '0',
          referrerpolicy: 'strict-origin-when-cross-origin',
        },
      ],
    ];
  },
});

const DownloadAssetBlock = Node.create({
  name: 'downloadAsset',
  group: 'block',
  atom: true,

  addAttributes() {
    return {
      url: { default: '' },
      label: { default: 'Download asset' },
    };
  },

  parseHTML() {
    return [{ tag: 'div[data-download-asset]' }];
  },

  renderHTML({ HTMLAttributes }) {
    return [
      'div',
      mergeAttributes(HTMLAttributes, {
        'data-download-asset': 'true',
        class: 'my-4 rounded-xl border border-gray-700 bg-gray-800/60 p-4',
      }),
      [
        'a',
        {
          href: HTMLAttributes.url || '#',
          class: 'inline-flex items-center rounded-lg border border-sky-500/40 bg-sky-500/10 px-3 py-2 text-sm text-sky-200',
          target: '_blank',
          rel: 'noopener noreferrer nofollow',
          download: 'true',
        },
        HTMLAttributes.label || 'Download asset',
      ],
    ];
  },
});

function createSlashCommandExtension(insert: {
  image: () => void;
  uploadImage: () => void;
  artwork: () => void;
  code: () => void;
  quote: () => void;
  divider: () => void;
  gallery: () => void;
  video: () => void;
  download: () => void;
}) {
  return Extension.create({
    name: 'slashCommands',

    addOptions() {
      return {
        suggestion: {
          char: '/',
          startOfLine: true,
          items: ({ query }: { query: string }) => {
            const all = [
              { title: 'Upload Image', key: 'uploadImage' },
              { title: 'Image', key: 'image' },
              { title: 'Artwork', key: 'artwork' },
              { title: 'Code', key: 'code' },
              { title: 'Quote', key: 'quote' },
              { title: 'Divider', key: 'divider' },
              { title: 'Gallery', key: 'gallery' },
              { title: 'Video', key: 'video' },
              { title: 'Download', key: 'download' },
            ];
            return all.filter((item) => item.key.startsWith(query.toLowerCase()));
          },
          command: ({ props }: { editor: any; props: { key: string } }) => {
            if (props.key === 'uploadImage') insert.uploadImage();
            if (props.key === 'image') insert.image();
            if (props.key === 'artwork') insert.artwork();
            if (props.key === 'code') insert.code();
            if (props.key === 'quote') insert.quote();
            if (props.key === 'divider') insert.divider();
            if (props.key === 'gallery') insert.gallery();
            if (props.key === 'video') insert.video();
            if (props.key === 'download') insert.download();
          },
          render: () => {
            let popup: any;
            let root: HTMLDivElement | null = null;
            let selected = 0;
            let items: Array<{ title: string; key: string }> = [];
            let command: ((item: { title: string; key: string }) => void) | null = null;

            const draw = () => {
              if (!root) return;
              root.innerHTML = items
                .map((item, index) => {
                  const active = index === selected ? 'bg-sky-500/20 text-sky-200' : 'text-gray-200';
                  return `<button data-index="${index}" class="block w-full rounded-md px-3 py-2 text-left text-sm ${active}">/${item.key} <span class="text-gray-400">${item.title}</span></button>`;
                })
                .join('');

              root.querySelectorAll('button').forEach((button) => {
                button.addEventListener('mousedown', (event) => {
                  event.preventDefault();
                  const idx = Number((event.currentTarget as HTMLButtonElement).dataset.index || 0);
                  const choice = items[idx];
                  if (choice && command) command(choice);
                });
              });
            };

            return {
              onStart: (props: any) => {
                items = props.items;
                command = props.command;
                selected = 0;
                root = document.createElement('div');
                root.className = 'w-52 rounded-lg border border-gray-700 bg-gray-900 p-1 shadow-xl';
                draw();

                popup = tippy('body', {
                  getReferenceClientRect: props.clientRect,
                  appendTo: () => document.body,
                  content: root,
                  showOnCreate: true,
                  interactive: true,
                  trigger: 'manual',
                  placement: 'bottom-start',
                });
              },
              onUpdate: (props: any) => {
                items = props.items;
                command = props.command;
                if (selected >= items.length) selected = 0;
                draw();
                popup?.[0]?.setProps({ getReferenceClientRect: props.clientRect });
              },
              onKeyDown: (props: any) => {
                if (props.event.key === 'ArrowDown') {
                  selected = (selected + 1) % Math.max(items.length, 1);
                  draw();
                  return true;
                }
                if (props.event.key === 'ArrowUp') {
                  selected = (selected + Math.max(items.length, 1) - 1) % Math.max(items.length, 1);
                  draw();
                  return true;
                }
                if (props.event.key === 'Enter') {
                  const choice = items[selected];
                  if (choice && command) command(choice);
                  return true;
                }
                if (props.event.key === 'Escape') {
                  popup?.[0]?.hide();
                  return true;
                }
                return false;
              },
              onExit: () => {
                popup?.[0]?.destroy();
                popup = null;
                root = null;
              },
            };
          },
        },
      };
    },

    addProseMirrorPlugins() {
      return [
        Suggestion({
          editor: this.editor,
          ...this.options.suggestion,
        }),
      ];
    },
  });
}

async function botHeaders(extra: Record<string, string> = {}, captcha: { token?: string } = {}) {
  const fingerprint = await buildBotFingerprint();

  return {
    ...extra,
    'X-Bot-Fingerprint': fingerprint,
    ...(captcha?.token ? { 'X-Captcha-Token': captcha.token } : {}),
  };
}

async function requestJson<T>(url: string, method: string, body: unknown, csrfToken: string, captcha: { token?: string } = {}): Promise<T> {
  const response = await fetch(url, {
    method,
    headers: await botHeaders({
      'Content-Type': 'application/json',
      'X-CSRF-TOKEN': csrfToken,
      'X-Requested-With': 'XMLHttpRequest',
    }, captcha),
    body: JSON.stringify(body),
  });

  const payload = await response.json().catch(() => ({}));

  if (!response.ok) {
    const error = new Error((payload as any)?.message || `Request failed: ${response.status}`) as Error & { status?: number; payload?: unknown };
    error.status = response.status;
    error.payload = payload;
    throw error;
  }

  return payload as T;
}

export default function StoryEditor({ mode, initialStory, storyTypes, endpoints, csrfToken }: Props) {
  const [storyId, setStoryId] = useState<number | undefined>(initialStory.id);
  const [title, setTitle] = useState(initialStory.title || '');
  const [excerpt, setExcerpt] = useState(initialStory.excerpt || '');
  const [coverImage, setCoverImage] = useState(initialStory.cover_image || '');
  const [storyType, setStoryType] = useState(initialStory.story_type || 'creator_story');
  const [tagsCsv, setTagsCsv] = useState(initialStory.tags_csv || '');
  const [metaTitle, setMetaTitle] = useState(initialStory.meta_title || '');
  const [metaDescription, setMetaDescription] = useState(initialStory.meta_description || '');
  const [canonicalUrl, setCanonicalUrl] = useState(initialStory.canonical_url || '');
  const [ogImage, setOgImage] = useState(initialStory.og_image || '');
  const [status, setStatus] = useState(initialStory.status || 'draft');
  const [scheduledFor, setScheduledFor] = useState(initialStory.scheduled_for || '');
  const [saveStatus, setSaveStatus] = useState('Autosave idle');
  const [artworkModalOpen, setArtworkModalOpen] = useState(false);
  const [artworkResults, setArtworkResults] = useState<Artwork[]>([]);
  const [artworkQuery, setArtworkQuery] = useState('');
  const [showInsertMenu, setShowInsertMenu] = useState(false);
  const [showLivePreview, setShowLivePreview] = useState(false);
  const [livePreviewHtml, setLivePreviewHtml] = useState('');
  const [inlineToolbar, setInlineToolbar] = useState({ visible: false, top: 0, left: 0 });
  const [fieldErrors, setFieldErrors] = useState<Record<string, string[]>>({});
  const [generalError, setGeneralError] = useState('');
  const [wordCount, setWordCount] = useState(0);
  const [readMinutes, setReadMinutes] = useState(1);
  const [codeBlockLanguage, setCodeBlockLanguage] = useState('bash');
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [captchaState, setCaptchaState] = useState({
    required: false,
    token: '',
    message: '',
    nonce: 0,
    provider: 'turnstile',
    siteKey: '',
    inputName: 'cf-turnstile-response',
    scriptUrl: '',
  });
  const lastSavedRef = useRef('');
  const editorRef = useRef<any>(null);
  const bodyImageInputRef = useRef<HTMLInputElement | null>(null);
  const coverImageInputRef = useRef<HTMLInputElement | null>(null);

  const emitSaveEvent = useCallback((kind: 'autosave' | 'manual', id?: number) => {
    window.dispatchEvent(new CustomEvent('story-editor:saved', {
      detail: {
        kind,
        storyId: id,
        savedAt: new Date().toISOString(),
      },
    }));
  }, []);

  const resetCaptchaState = useCallback(() => {
    setCaptchaState((prev) => ({
      ...prev,
      required: false,
      token: '',
      message: '',
      nonce: prev.nonce + 1,
    }));
  }, []);

  const captureCaptchaRequirement = useCallback((payload: any = {}) => {
    const requiresCaptcha = !!(payload?.requires_captcha || payload?.requiresCaptcha);
    if (!requiresCaptcha) {
      return false;
    }

    const nextCaptcha = payload?.captcha || {};
    const message = payload?.errors?.captcha?.[0] || payload?.message || 'Complete the captcha challenge to continue.';

    setCaptchaState((prev) => ({
      required: true,
      token: '',
      message,
      nonce: prev.nonce + 1,
      provider: nextCaptcha.provider || payload?.captcha_provider || prev.provider || 'turnstile',
      siteKey: nextCaptcha.siteKey || payload?.captcha_site_key || prev.siteKey || '',
      inputName: nextCaptcha.inputName || payload?.captcha_input || prev.inputName || 'cf-turnstile-response',
      scriptUrl: nextCaptcha.scriptUrl || payload?.captcha_script_url || prev.scriptUrl || '',
    }));

    return true;
  }, []);

  const applyFailure = useCallback((error: any, fallback: string) => {
    const payload = error?.payload || {};
    const nextErrors = payload?.errors && typeof payload.errors === 'object' ? payload.errors : {};
    setFieldErrors(nextErrors);
    const requiresCaptcha = captureCaptchaRequirement(payload);
    const message = nextErrors?.captcha?.[0]
      || nextErrors?.title?.[0]
      || nextErrors?.content?.[0]
      || payload?.message
      || fallback;
    setGeneralError(message);
    setSaveStatus(requiresCaptcha ? 'Captcha required' : message);
  }, [captureCaptchaRequirement]);

  const clearFeedback = useCallback(() => {
    setGeneralError('');
    setFieldErrors({});
  }, []);

  const openLinkPrompt = useCallback((editor: any) => {
    const prev = editor.getAttributes('link').href;
    const url = window.prompt('Link URL', prev || 'https://');
    if (url === null) return;
    if (url.trim() === '') {
      editor.chain().focus().unsetLink().run();
      return;
    }
    editor.chain().focus().setLink({ href: url.trim() }).run();
  }, []);

  const fetchArtworks = useCallback(async (query: string) => {
    const q = encodeURIComponent(query);
    const response = await fetch(`${endpoints.artworks}?q=${q}`, {
      headers: {
        'X-Requested-With': 'XMLHttpRequest',
      },
    });
    if (!response.ok) return;
    const data = await response.json();
    setArtworkResults(Array.isArray(data.artworks) ? data.artworks : []);
  }, [endpoints.artworks]);

  const uploadImageFile = useCallback(async (file: File): Promise<string | null> => {
    const formData = new FormData();
    formData.append('image', file);

    const response = await fetch(endpoints.uploadImage, {
      method: 'POST',
      headers: await botHeaders({
        'X-CSRF-TOKEN': csrfToken,
        'X-Requested-With': 'XMLHttpRequest',
      }, captchaState),
      body: formData,
    });

    const payload = await response.json().catch(() => ({}));

    if (!response.ok) {
      setFieldErrors(payload?.errors && typeof payload.errors === 'object' ? payload.errors : {});
      captureCaptchaRequirement(payload);
      setGeneralError(payload?.errors?.captcha?.[0] || payload?.message || 'Image upload failed');
      return null;
    }

    clearFeedback();
    if (captchaState.required && captchaState.token) {
      resetCaptchaState();
    }

    const data = payload;
    return data.medium_url || data.original_url || data.thumbnail_url || null;
  }, [captchaState, captureCaptchaRequirement, clearFeedback, endpoints.uploadImage, csrfToken, resetCaptchaState]);

  const applyCodeBlockLanguage = useCallback((language: string) => {
    const nextLanguage = (language || 'plaintext').trim() || 'plaintext';
    setCodeBlockLanguage(nextLanguage);

    const currentEditor = editorRef.current;
    if (!currentEditor || !currentEditor.isActive('codeBlock')) {
      return;
    }

    currentEditor.chain().focus().updateAttributes('codeBlock', { language: nextLanguage }).run();
  }, []);

  const toggleCodeBlockWithLanguage = useCallback(() => {
    const currentEditor = editorRef.current;
    if (!currentEditor) return;

    if (currentEditor.isActive('codeBlock')) {
      currentEditor.chain().focus().toggleCodeBlock().run();
      return;
    }

    currentEditor.chain().focus().setCodeBlock({ language: codeBlockLanguage }).run();
  }, [codeBlockLanguage]);

  const insertActions = useMemo(() => ({
    image: () => {
      const currentEditor = editorRef.current;
      const url = window.prompt('Image URL', 'https://');
      if (!url || !currentEditor) return;
      currentEditor.chain().focus().setImage({ src: url }).run();
    },
    uploadImage: () => bodyImageInputRef.current?.click(),
    artwork: () => setArtworkModalOpen(true),
    code: () => {
      toggleCodeBlockWithLanguage();
    },
    quote: () => {
      const currentEditor = editorRef.current;
      if (!currentEditor) return;
      currentEditor.chain().focus().toggleBlockquote().run();
    },
    divider: () => {
      const currentEditor = editorRef.current;
      if (!currentEditor) return;
      currentEditor.chain().focus().setHorizontalRule().run();
    },
    gallery: () => {
      const currentEditor = editorRef.current;
      if (!currentEditor) return;
      const raw = window.prompt('Gallery image URLs (comma separated)', '');
      const images = (raw || '').split(',').map((value) => value.trim()).filter(Boolean);
      currentEditor.chain().focus().insertContent({ type: 'galleryBlock', attrs: { images } }).run();
    },
    video: () => {
      const currentEditor = editorRef.current;
      if (!currentEditor) return;
      const src = window.prompt('Video embed URL (YouTube/Vimeo)', 'https://www.youtube.com/embed/');
      if (!src) return;
      currentEditor.chain().focus().insertContent({ type: 'videoEmbed', attrs: { src, title: 'Embedded video' } }).run();
    },
    download: () => {
      const currentEditor = editorRef.current;
      if (!currentEditor) return;
      const url = window.prompt('Download URL', 'https://');
      if (!url) return;
      const label = window.prompt('Button label', 'Download asset') || 'Download asset';
      currentEditor.chain().focus().insertContent({ type: 'downloadAsset', attrs: { url, label } }).run();
    },
  }), [toggleCodeBlockWithLanguage]);

  const editor = useEditor({
    extensions: [
      StarterKit.configure({
        codeBlock: false,
        heading: { levels: [1, 2, 3] },
      }),
      CodeBlockLowlight.configure({
        lowlight,
      }),
      Underline,
      Image,
      Link.configure({
        openOnClick: false,
        HTMLAttributes: {
          class: 'text-sky-300 underline',
          rel: 'noopener noreferrer nofollow',
          target: '_blank',
        },
      }),
      Placeholder.configure({
        placeholder: 'Start writing your story...',
      }),
      ArtworkBlock,
      GalleryBlock,
      VideoEmbedBlock,
      DownloadAssetBlock,
      createSlashCommandExtension(insertActions),
    ],
    content: initialStory.content || EMPTY_DOC,
    editorProps: {
      attributes: {
        class: 'tiptap prose prose-invert prose-headings:tracking-tight prose-p:text-[1.04rem] prose-p:leading-8 prose-p:text-stone-200 prose-strong:text-white prose-a:text-sky-300 prose-blockquote:border-l-sky-400 prose-blockquote:text-stone-300 prose-code:text-sky-200 max-w-none min-h-[32rem] bg-transparent px-0 py-0 text-stone-200 focus:outline-none',
      },
      handleDrop: (_view, event) => {
        const file = event.dataTransfer?.files?.[0];
        if (!file || !file.type.startsWith('image/')) return false;

        void (async () => {
          setSaveStatus('Uploading image...');
          const uploaded = await uploadImageFile(file);
          if (uploaded && editor) {
            editor.chain().focus().setImage({ src: uploaded }).run();
            setSaveStatus('Image uploaded');
          } else {
            setSaveStatus('Image upload failed');
          }
        })();

        return true;
      },
      handlePaste: (_view, event) => {
        const file = event.clipboardData?.files?.[0];
        if (!file || !file.type.startsWith('image/')) return false;

        void (async () => {
          setSaveStatus('Uploading image...');
          const uploaded = await uploadImageFile(file);
          if (uploaded && editor) {
            editor.chain().focus().setImage({ src: uploaded }).run();
            setSaveStatus('Image uploaded');
          } else {
            setSaveStatus('Image upload failed');
          }
        })();

        return true;
      },
    },
  });

  editorRef.current = editor;

  useEffect(() => {
    if (!editor) return;

    const updatePreview = () => {
      setLivePreviewHtml(editor.getHTML());
      const text = editor.getText().replace(/\s+/g, ' ').trim();
      const words = text === '' ? 0 : text.split(' ').length;
      setWordCount(words);
      setReadMinutes(Math.max(1, Math.ceil(words / 200)));
    };

    updatePreview();
    editor.on('update', updatePreview);

    return () => {
      editor.off('update', updatePreview);
    };
  }, [editor]);

  useEffect(() => {
    if (!editor) return;

    const syncCodeBlockLanguage = () => {
      if (!editor.isActive('codeBlock')) {
        return;
      }

      const nextLanguage = String(editor.getAttributes('codeBlock').language || '').trim();
      if (nextLanguage !== '') {
        setCodeBlockLanguage(nextLanguage);
      }
    };

    syncCodeBlockLanguage();
    editor.on('selectionUpdate', syncCodeBlockLanguage);
    editor.on('update', syncCodeBlockLanguage);

    return () => {
      editor.off('selectionUpdate', syncCodeBlockLanguage);
      editor.off('update', syncCodeBlockLanguage);
    };
  }, [editor]);

  useEffect(() => {
    if (!artworkModalOpen) return;
    void fetchArtworks(artworkQuery);
  }, [artworkModalOpen, artworkQuery, fetchArtworks]);

  useEffect(() => {
    if (!editor) return;

    const updateToolbar = () => {
      const { from, to } = editor.state.selection;
      if (from === to) {
        setInlineToolbar({ visible: false, top: 0, left: 0 });
        return;
      }

      const start = editor.view.coordsAtPos(from);
      const end = editor.view.coordsAtPos(to);
      setInlineToolbar({
        visible: true,
        top: Math.max(10, start.top + window.scrollY - 48),
        left: Math.max(10, (start.left + end.right) / 2 + window.scrollX - 120),
      });
    };

    editor.on('selectionUpdate', updateToolbar);
    editor.on('blur', () => setInlineToolbar({ visible: false, top: 0, left: 0 }));

    return () => {
      editor.off('selectionUpdate', updateToolbar);
    };
  }, [editor]);

  const payload = useCallback(() => ({
    story_id: storyId,
    title,
    excerpt,
    cover_image: coverImage,
    story_type: storyType,
    tags_csv: tagsCsv,
    tags: tagsCsv.split(',').map((tag) => tag.trim()).filter(Boolean),
    meta_title: metaTitle || title,
    meta_description: metaDescription || excerpt,
    canonical_url: canonicalUrl,
    og_image: ogImage || coverImage,
    status,
    scheduled_for: scheduledFor || null,
    content: editor?.getJSON() || EMPTY_DOC,
  }), [storyId, title, excerpt, coverImage, storyType, tagsCsv, metaTitle, metaDescription, canonicalUrl, ogImage, status, scheduledFor, editor]);

  useEffect(() => {
    if (!editor) return;

    const timer = window.setInterval(async () => {
      if (isSubmitting) {
        return;
      }

      const body = payload();
      const snapshot = JSON.stringify(body);
      if (snapshot === lastSavedRef.current) {
        return;
      }

      try {
        clearFeedback();
        setSaveStatus('Saving...');
        const data = await requestJson<{ story_id?: number; message?: string; edit_url?: string }>(
          endpoints.autosave,
          'POST',
          captchaState.required && captchaState.inputName ? {
            ...body,
            [captchaState.inputName]: captchaState.token || '',
          } : body,
          csrfToken,
          captchaState,
        );
        if (data.story_id && !storyId) {
          setStoryId(data.story_id);
        }
        if (data.edit_url && window.location.pathname.endsWith('/create')) {
          window.history.replaceState({}, '', data.edit_url);
        }
        lastSavedRef.current = snapshot;
        setSaveStatus(data.message || 'Saved just now');
        if (captchaState.required && captchaState.token) {
          resetCaptchaState();
        }
        emitSaveEvent('autosave', data.story_id || storyId);
      } catch (error) {
        applyFailure(error, 'Autosave failed');
      }
    }, 10000);

    return () => window.clearInterval(timer);
  }, [applyFailure, captchaState, clearFeedback, csrfToken, editor, emitSaveEvent, endpoints.autosave, isSubmitting, payload, resetCaptchaState, storyId]);

  const persistStory = async (submitAction: 'save_draft' | 'submit_review' | 'publish_now' | 'schedule_publish') => {
    const body = {
      ...payload(),
      submit_action: submitAction,
      status: submitAction === 'submit_review' ? 'pending_review' : submitAction === 'publish_now' ? 'published' : submitAction === 'schedule_publish' ? 'scheduled' : status,
      scheduled_for: submitAction === 'schedule_publish' ? scheduledFor : null,
    };

    try {
      clearFeedback();
      setIsSubmitting(true);
      setSaveStatus('Saving...');
      const endpoint = storyId ? endpoints.update : endpoints.create;
      const method = storyId ? 'PUT' : 'POST';
      const data = await requestJson<{ story_id: number; message?: string; status?: string; edit_url?: string; public_url?: string }>(endpoint, method, captchaState.required && captchaState.inputName ? {
        ...body,
        [captchaState.inputName]: captchaState.token || '',
      } : body, csrfToken, captchaState);
      if (data.story_id) {
        setStoryId(data.story_id);
      }
      if (data.edit_url && window.location.pathname.endsWith('/create')) {
        window.history.replaceState({}, '', data.edit_url);
      }
      lastSavedRef.current = JSON.stringify(payload());
      setSaveStatus(data.message || 'Saved just now');
      if (captchaState.required && captchaState.token) {
        resetCaptchaState();
      }
      emitSaveEvent('manual', data.story_id || storyId);
      if (submitAction === 'publish_now' && data.public_url) {
        window.location.assign(data.public_url);
        return;
      }
    } catch (error) {
      applyFailure(error, submitAction === 'publish_now' ? 'Publish failed' : 'Save failed');
    } finally {
      setIsSubmitting(false);
    }
  };

  const handleBodyImagePicked = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    event.target.value = '';
    if (!file) return;

    setSaveStatus('Uploading image...');
    const uploaded = await uploadImageFile(file);
    if (!uploaded || !editor) {
      setSaveStatus('Image upload failed');
      return;
    }

    editor.chain().focus().setImage({ src: uploaded }).run();
    setSaveStatus('Image uploaded');
  };

  const handleCoverImagePicked = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    event.target.value = '';
    if (!file) return;

    setSaveStatus('Uploading cover...');
    const uploaded = await uploadImageFile(file);
    if (!uploaded) {
      setSaveStatus('Cover upload failed');
      return;
    }

    setCoverImage(uploaded);
    setSaveStatus('Cover uploaded');
  };

  const readinessChecks = useMemo(() => ([
    { label: 'Title', ok: title.trim().length > 0, hint: 'Give the story a clear headline.' },
    { label: 'Body', ok: wordCount >= 50, hint: 'Aim for at least 50 words before publishing.' },
    { label: 'Story type', ok: storyType.trim().length > 0, hint: 'Choose the format that fits the post.' },
  ]), [storyType, title, wordCount]);

  const titleError = fieldErrors?.title?.[0] || '';
  const contentError = fieldErrors?.content?.[0] || '';
  const excerptError = fieldErrors?.excerpt?.[0] || '';
  const tagsError = fieldErrors?.tags_csv?.[0] || '';

  const insertArtwork = (item: Artwork) => {
    if (!editor) return;
    editor.chain().focus().insertContent({
      type: 'artworkEmbed',
      attrs: {
        artworkId: item.id,
        title: item.title,
        url: item.url,
        thumb: item.thumbs?.md || item.thumbs?.sm || item.thumb || '',
      },
    }).run();
    setArtworkModalOpen(false);
  };

  return (
    <div className="space-y-6">
      <div className="sticky top-16 z-30 overflow-hidden rounded-[1.5rem] border border-white/10 bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.18),_transparent_28%),linear-gradient(135deg,rgba(12,18,28,0.96),rgba(10,14,22,0.92))] p-4 shadow-[0_20px_70px_rgba(3,7,18,0.26)] backdrop-blur-xl">
        <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
          <div className="space-y-2">
            <div className="flex flex-wrap items-center gap-2 text-xs uppercase tracking-[0.24em] text-white/45">
              <span className="rounded-full border border-white/10 bg-white/[0.06] px-2.5 py-1 text-[11px] font-semibold text-white/70">{mode === 'create' ? 'New story' : 'Editing draft'}</span>
              <span>{wordCount.toLocaleString()} words</span>
              <span>{readMinutes} min read</span>
              <span>{saveStatus}</span>
            </div>
            <p className="max-w-2xl text-sm text-white/62">Write in the main column, keep the sidebar for story settings, and only surface captcha when protection actually asks for it.</p>
          </div>

          <div className="flex flex-wrap items-center gap-2">
            <button type="button" onClick={() => setShowInsertMenu((current) => !current)} className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white/78 transition hover:bg-white/[0.09]">Insert block</button>
            <button type="button" onClick={() => setShowLivePreview((current) => !current)} className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white/78 transition hover:bg-white/[0.09]">{showLivePreview ? 'Hide preview' : 'Preview'}</button>
            <button type="button" onClick={() => persistStory('save_draft')} disabled={isSubmitting} className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white transition hover:bg-white/[0.09] disabled:opacity-60">Save draft</button>
            <button type="button" onClick={() => persistStory('submit_review')} disabled={isSubmitting} className="rounded-xl border border-amber-400/30 bg-amber-400/12 px-3 py-2 text-sm text-amber-100 transition hover:bg-amber-400/20 disabled:opacity-60">Submit review</button>
            <button type="button" onClick={() => persistStory('publish_now')} disabled={isSubmitting} className="rounded-xl border border-emerald-400/30 bg-emerald-400/14 px-3 py-2 text-sm font-medium text-emerald-100 transition hover:bg-emerald-400/22 disabled:opacity-60">Publish now</button>
          </div>
        </div>
      </div>

      <div className="grid gap-6 xl:grid-cols-[minmax(0,1fr)_22rem]">
        <div className="space-y-6">
          <section className="overflow-hidden rounded-[2rem] border border-white/10 bg-[radial-gradient(circle_at_top_left,_rgba(251,191,36,0.12),_transparent_26%),linear-gradient(180deg,rgba(16,22,33,0.96),rgba(9,12,19,0.92))] shadow-[0_22px_80px_rgba(4,8,20,0.24)]">
            {coverImage ? (
              <div className="relative h-56 overflow-hidden border-b border-white/10">
                <img src={coverImage} alt="Story cover" className="h-full w-full object-cover" />
                <div className="absolute inset-0 bg-gradient-to-t from-slate-950 via-slate-950/25 to-transparent" />
                <div className="absolute bottom-4 left-4 rounded-full border border-white/15 bg-black/35 px-3 py-1 text-xs uppercase tracking-[0.24em] text-white/75">Cover preview</div>
              </div>
            ) : null}

            <div className="space-y-5 p-6 md:p-8">
              <div className="flex flex-wrap items-center gap-3 text-xs uppercase tracking-[0.22em] text-white/42">
                <span>{storyTypes.find((type) => type.slug === storyType)?.name || 'Story'}</span>
                <span>{status.replace(/_/g, ' ')}</span>
                {scheduledFor ? <span>Scheduled {scheduledFor}</span> : null}
              </div>

              <div>
                <input
                  value={title}
                  onChange={(event) => setTitle(event.target.value)}
                  placeholder="Give the story a title worth opening"
                  className="w-full border-0 bg-transparent px-0 text-4xl font-semibold tracking-tight text-white placeholder:text-white/25 focus:outline-none md:text-5xl"
                />
                {titleError ? <p className="mt-2 text-sm text-rose-300">{titleError}</p> : null}
              </div>

              <div>
                <textarea
                  value={excerpt}
                  onChange={(event) => setExcerpt(event.target.value)}
                  placeholder="Write a short dek that explains why this story matters."
                  rows={3}
                  className="w-full resize-none border-0 bg-transparent px-0 text-base leading-7 text-white/70 placeholder:text-white/25 focus:outline-none"
                />
                {excerptError ? <p className="mt-2 text-sm text-rose-300">{excerptError}</p> : null}
              </div>

              <div className="grid gap-3 sm:grid-cols-3">
                <div className="rounded-2xl border border-white/10 bg-white/[0.04] p-4">
                  <p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-white/38">Words</p>
                  <p className="mt-2 text-2xl font-semibold text-white">{wordCount.toLocaleString()}</p>
                </div>
                <div className="rounded-2xl border border-white/10 bg-white/[0.04] p-4">
                  <p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-white/38">Reading time</p>
                  <p className="mt-2 text-2xl font-semibold text-white">{readMinutes} min</p>
                </div>
                <div className="rounded-2xl border border-white/10 bg-white/[0.04] p-4">
                  <p className="text-[11px] font-semibold uppercase tracking-[0.2em] text-white/38">Status</p>
                  <p className="mt-2 text-2xl font-semibold capitalize text-white">{status.replace(/_/g, ' ')}</p>
                </div>
              </div>
            </div>
          </section>

          <section className="relative overflow-hidden rounded-[2rem] border border-white/10 bg-[linear-gradient(180deg,rgba(16,19,28,0.98),rgba(8,10,17,0.96))] shadow-[0_24px_90px_rgba(4,8,20,0.28)]">
            <div className="border-b border-white/10 px-5 py-4">
              <div className="flex flex-wrap items-center gap-2">
                {editor ? (
                  <>
                    <button type="button" className={`rounded-xl px-3 py-2 text-sm ${editor.isActive('bold') ? 'bg-sky-400/20 text-sky-100' : 'bg-white/[0.05] text-white/75'}`} onClick={() => editor.chain().focus().toggleBold().run()}>Bold</button>
                    <button type="button" className={`rounded-xl px-3 py-2 text-sm ${editor.isActive('italic') ? 'bg-sky-400/20 text-sky-100' : 'bg-white/[0.05] text-white/75'}`} onClick={() => editor.chain().focus().toggleItalic().run()}>Italic</button>
                    <button type="button" className={`rounded-xl px-3 py-2 text-sm ${editor.isActive('underline') ? 'bg-sky-400/20 text-sky-100' : 'bg-white/[0.05] text-white/75'}`} onClick={() => editor.chain().focus().toggleUnderline().run()}>Underline</button>
                    <button type="button" className={`rounded-xl px-3 py-2 text-sm ${editor.isActive('heading', { level: 2 }) ? 'bg-sky-400/20 text-sky-100' : 'bg-white/[0.05] text-white/75'}`} onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}>H2</button>
                    <button type="button" className={`rounded-xl px-3 py-2 text-sm ${editor.isActive('heading', { level: 3 }) ? 'bg-sky-400/20 text-sky-100' : 'bg-white/[0.05] text-white/75'}`} onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}>H3</button>
                    <button type="button" className={`rounded-xl px-3 py-2 text-sm ${editor.isActive('bulletList') ? 'bg-sky-400/20 text-sky-100' : 'bg-white/[0.05] text-white/75'}`} onClick={() => editor.chain().focus().toggleBulletList().run()}>Bullets</button>
                    <button type="button" className={`rounded-xl px-3 py-2 text-sm ${editor.isActive('orderedList') ? 'bg-sky-400/20 text-sky-100' : 'bg-white/[0.05] text-white/75'}`} onClick={() => editor.chain().focus().toggleOrderedList().run()}>Numbers</button>
                    <button type="button" className={`rounded-xl px-3 py-2 text-sm ${editor.isActive('blockquote') ? 'bg-sky-400/20 text-sky-100' : 'bg-white/[0.05] text-white/75'}`} onClick={() => editor.chain().focus().toggleBlockquote().run()}>Quote</button>
                    <button type="button" className={`rounded-xl px-3 py-2 text-sm ${editor.isActive('codeBlock') ? 'bg-sky-400/20 text-sky-100' : 'bg-white/[0.05] text-white/75'}`} onClick={toggleCodeBlockWithLanguage}>Code block</button>
                    <div className="inline-flex items-center gap-2 rounded-xl bg-white/[0.05] px-3 py-2 text-sm text-white/75">
                      <span className="text-white/50">Lang</span>
                      <div className="min-w-[10rem]">
                        <Select
                          value={codeBlockLanguage}
                          onChange={(event) => applyCodeBlockLanguage(event.target.value)}
                          options={CODE_BLOCK_LANGUAGES}
                          size="sm"
                          className="border-white/10 bg-slate-950/90 py-1 text-sm text-white hover:border-white/20"
                        />
                      </div>
                    </div>
                    <button type="button" className="rounded-xl bg-white/[0.05] px-3 py-2 text-sm text-white/75" onClick={() => openLinkPrompt(editor)}>Link</button>
                  </>
                ) : null}
              </div>
            </div>

            {showInsertMenu && (
              <div className="border-b border-white/10 bg-white/[0.03] px-5 py-4">
                <div className="grid grid-cols-2 gap-2 sm:grid-cols-3 xl:grid-cols-4">
                  <button type="button" className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white/80" onClick={insertActions.uploadImage}>Upload image</button>
                  <button type="button" className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white/80" onClick={insertActions.image}>Image URL</button>
                  <button type="button" className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white/80" onClick={insertActions.artwork}>Embed artwork</button>
                  <button type="button" className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white/80" onClick={insertActions.gallery}>Gallery</button>
                  <button type="button" className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white/80" onClick={insertActions.video}>Video</button>
                  <button type="button" className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white/80" onClick={insertActions.download}>Download</button>
                  <button type="button" className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white/80" onClick={insertActions.quote}>Quote</button>
                  <button type="button" className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-sm text-white/80" onClick={insertActions.code}>Code block</button>
                  <div className="col-span-2 rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 sm:col-span-3 xl:col-span-2">
                    <div className="mb-2 text-sm text-white/45">Language</div>
                    <Select
                      value={codeBlockLanguage}
                      onChange={(event) => applyCodeBlockLanguage(event.target.value)}
                      options={CODE_BLOCK_LANGUAGES}
                      size="sm"
                      className="border-white/10 bg-slate-950/90 text-white hover:border-white/20"
                    />
                  </div>
                </div>
              </div>
            )}

            {editor && inlineToolbar.visible && (
              <div
                className="fixed z-40 flex items-center gap-1 rounded-2xl border border-white/10 bg-slate-950/95 px-2 py-1 shadow-lg backdrop-blur"
                style={{ top: `${inlineToolbar.top}px`, left: `${inlineToolbar.left}px` }}
              >
                <button type="button" className={`rounded px-2 py-1 text-xs ${editor.isActive('bold') ? 'bg-sky-500/30 text-sky-100' : 'text-gray-200'}`} onMouseDown={(event) => event.preventDefault()} onClick={() => editor.chain().focus().toggleBold().run()}>B</button>
                <button type="button" className={`rounded px-2 py-1 text-xs ${editor.isActive('italic') ? 'bg-sky-500/30 text-sky-100' : 'text-gray-200'}`} onMouseDown={(event) => event.preventDefault()} onClick={() => editor.chain().focus().toggleItalic().run()}>I</button>
                <button type="button" className={`rounded px-2 py-1 text-xs ${editor.isActive('underline') ? 'bg-sky-500/30 text-sky-100' : 'text-gray-200'}`} onMouseDown={(event) => event.preventDefault()} onClick={() => editor.chain().focus().toggleUnderline().run()}>U</button>
                <button type="button" className={`rounded px-2 py-1 text-xs ${editor.isActive('code') ? 'bg-sky-500/30 text-sky-100' : 'text-gray-200'}`} onMouseDown={(event) => event.preventDefault()} onClick={() => editor.chain().focus().toggleCode().run()}>{'</>'}</button>
                <button type="button" className="rounded px-2 py-1 text-xs text-gray-200" onMouseDown={(event) => event.preventDefault()} onClick={() => openLinkPrompt(editor)}>Link</button>
              </div>
            )}

            <div className="px-6 py-8 md:px-10 md:py-10">
              <EditorContent editor={editor} />
              {contentError ? <p className="mt-4 text-sm text-rose-300">{contentError}</p> : null}
            </div>

            {showLivePreview && (
              <div className="border-t border-white/10 bg-white/[0.02] px-6 py-6 md:px-10">
                <div className="mb-3 text-xs font-semibold uppercase tracking-[0.22em] text-white/40">Live preview</div>
                <div className="prose prose-invert max-w-none prose-pre:bg-slate-950 prose-p:text-stone-200" dangerouslySetInnerHTML={{ __html: livePreviewHtml }} />
              </div>
            )}
          </section>
        </div>

        <aside className="space-y-4 xl:sticky xl:top-24 self-start">
          {(generalError || captchaState.required) && (
            <section className="rounded-[1.5rem] border border-amber-400/20 bg-amber-500/10 p-5">
              <p className="text-xs font-semibold uppercase tracking-[0.22em] text-amber-100/70">Action needed</p>
              <p className="mt-3 text-sm text-amber-50">{generalError || captchaState.message || 'Complete the captcha challenge to continue.'}</p>
              {captchaState.required && captchaState.siteKey ? (
                <div className="mt-4 rounded-2xl border border-white/10 bg-black/20 p-3">
                  <TurnstileField
                    key={`story-editor-captcha-${captchaState.nonce}`}
                    provider={captchaState.provider}
                    siteKey={captchaState.siteKey}
                    scriptUrl={captchaState.scriptUrl}
                    onToken={(token) => setCaptchaState((prev) => ({ ...prev, token }))}
                    className="min-h-16"
                  />
                </div>
              ) : null}
            </section>
          )}

          <section className="rounded-[1.5rem] border border-white/10 bg-white/[0.03] p-5">
            <p className="text-xs font-semibold uppercase tracking-[0.22em] text-white/38">Publish checklist</p>
            <div className="mt-4 space-y-3">
              {readinessChecks.map((item) => (
                <div key={item.label} className="rounded-2xl border border-white/8 bg-black/10 px-4 py-3">
                  <div className="flex items-center justify-between gap-3">
                    <span className="text-sm font-medium text-white">{item.label}</span>
                    <span className={`text-xs font-semibold uppercase tracking-[0.18em] ${item.ok ? 'text-emerald-300' : 'text-amber-200'}`}>{item.ok ? 'Ready' : 'Needs work'}</span>
                  </div>
                  <p className="mt-2 text-sm text-white/48">{item.hint}</p>
                </div>
              ))}
            </div>
          </section>

          <section className="rounded-[1.5rem] border border-white/10 bg-white/[0.03] p-5">
            <p className="text-xs font-semibold uppercase tracking-[0.22em] text-white/38">Story settings</p>
            <div className="mt-4 space-y-4">
              <div>
                <label className="mb-2 block text-sm font-medium text-white/80">Story type</label>
                <select value={storyType} onChange={(event) => setStoryType(event.target.value)} className="w-full rounded-xl border border-white/10 bg-slate-950/80 px-3 py-2.5 text-sm text-white">
                  {storyTypes.map((type) => (
                    <option key={type.slug} value={type.slug}>{type.name}</option>
                  ))}
                </select>
              </div>

              <div>
                <label className="mb-2 block text-sm font-medium text-white/80">Tags</label>
                <input value={tagsCsv} onChange={(event) => setTagsCsv(event.target.value)} placeholder="art direction, process, workflow" className="w-full rounded-xl border border-white/10 bg-slate-950/80 px-3 py-2.5 text-sm text-white placeholder:text-white/25" />
                {tagsError ? <p className="mt-2 text-sm text-rose-300">{tagsError}</p> : <p className="mt-2 text-xs text-white/40">Comma-separated. New tags are created automatically.</p>}
              </div>

              <div>
                <label className="mb-2 block text-sm font-medium text-white/80">Workflow status</label>
                <select value={status} onChange={(event) => setStatus(event.target.value)} className="w-full rounded-xl border border-white/10 bg-slate-950/80 px-3 py-2.5 text-sm text-white">
                  <option value="draft">Draft</option>
                  <option value="pending_review">Pending Review</option>
                  <option value="published">Published</option>
                  <option value="scheduled">Scheduled</option>
                  <option value="archived">Archived</option>
                </select>
              </div>

              <div>
                <label className="mb-2 block text-sm font-medium text-white/80">Schedule publish</label>
                <input type="datetime-local" value={scheduledFor} onChange={(event) => setScheduledFor(event.target.value)} className="w-full rounded-xl border border-white/10 bg-slate-950/80 px-3 py-2.5 text-sm text-white" />
              </div>
            </div>
          </section>

          <section className="rounded-[1.5rem] border border-white/10 bg-white/[0.03] p-5">
            <div className="flex items-center justify-between gap-3">
              <p className="text-xs font-semibold uppercase tracking-[0.22em] text-white/38">Cover</p>
              <button type="button" onClick={() => coverImageInputRef.current?.click()} className="rounded-xl border border-white/10 bg-white/[0.05] px-3 py-2 text-xs text-white/78">Upload</button>
            </div>
            <div className="mt-4 space-y-3">
              <input value={coverImage} onChange={(event) => setCoverImage(event.target.value)} placeholder="https://..." className="w-full rounded-xl border border-white/10 bg-slate-950/80 px-3 py-2.5 text-sm text-white placeholder:text-white/25" />
              {coverImage ? <img src={coverImage} alt="Cover preview" className="h-40 w-full rounded-2xl object-cover" /> : <div className="rounded-2xl border border-dashed border-white/10 px-4 py-8 text-center text-sm text-white/38">Add a cover image to give the story more presence in feeds.</div>}
            </div>
          </section>

          <section className="rounded-[1.5rem] border border-white/10 bg-white/[0.03] p-5">
            <p className="text-xs font-semibold uppercase tracking-[0.22em] text-white/38">SEO & social</p>
            <div className="mt-4 space-y-3">
              <input value={metaTitle} onChange={(event) => setMetaTitle(event.target.value)} placeholder="Meta title" className="w-full rounded-xl border border-white/10 bg-slate-950/80 px-3 py-2.5 text-sm text-white placeholder:text-white/25" />
              <textarea value={metaDescription} onChange={(event) => setMetaDescription(event.target.value)} rows={3} placeholder="Meta description" className="w-full resize-none rounded-xl border border-white/10 bg-slate-950/80 px-3 py-2.5 text-sm text-white placeholder:text-white/25" />
              <input value={canonicalUrl} onChange={(event) => setCanonicalUrl(event.target.value)} placeholder="Canonical URL" className="w-full rounded-xl border border-white/10 bg-slate-950/80 px-3 py-2.5 text-sm text-white placeholder:text-white/25" />
              <input value={ogImage} onChange={(event) => setOgImage(event.target.value)} placeholder="OG image URL" className="w-full rounded-xl border border-white/10 bg-slate-950/80 px-3 py-2.5 text-sm text-white placeholder:text-white/25" />
            </div>
          </section>
        </aside>
      </div>

      <div className="flex flex-wrap gap-3">
        {storyId && (
          <a href={`${endpoints.previewBase}/${storyId}/preview`} className="rounded-xl border border-sky-500/40 bg-sky-500/10 px-3 py-2 text-sm text-sky-200">Preview</a>
        )}
        {storyId && (
          <a href={`${endpoints.analyticsBase}/${storyId}/analytics`} className="rounded-xl border border-violet-500/40 bg-violet-500/10 px-3 py-2 text-sm text-violet-200">Analytics</a>
        )}
        {mode === 'edit' && storyId && (
          <form method="POST" action={`/creator/stories/${storyId}`} onSubmit={(event) => {
            if (!window.confirm('Delete this story?')) {
              event.preventDefault();
            }
          }}>
            <input type="hidden" name="_token" value={csrfToken} />
            <input type="hidden" name="_method" value="DELETE" />
            <button type="submit" className="rounded-xl border border-rose-500/40 bg-rose-500/20 px-3 py-2 text-sm text-rose-200">Delete</button>
          </form>
        )}
      </div>

      <input ref={bodyImageInputRef} type="file" accept="image/*" className="hidden" onChange={handleBodyImagePicked} />
      <input ref={coverImageInputRef} type="file" accept="image/*" className="hidden" onChange={handleCoverImagePicked} />

      {artworkModalOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 p-4">
          <div className="w-full max-w-3xl rounded-xl border border-gray-700 bg-gray-900 p-4 shadow-lg">
            <div className="mb-3 flex items-center justify-between">
              <h3 className="text-sm font-semibold text-white">Embed Artwork</h3>
              <button type="button" onClick={() => setArtworkModalOpen(false)} className="rounded border border-gray-600 px-2 py-1 text-xs text-gray-200">Close</button>
            </div>
            <input value={artworkQuery} onChange={(event) => setArtworkQuery(event.target.value)} className="mb-3 w-full rounded-xl border border-gray-700 bg-gray-800 px-3 py-2 text-sm text-gray-200" placeholder="Search artworks" />
            <div className="grid max-h-80 gap-3 overflow-y-auto sm:grid-cols-2">
              {artworkResults.map((item) => (
                <button key={item.id} type="button" onClick={() => insertArtwork(item)} className="rounded-xl border border-gray-700 bg-gray-800 p-3 text-left hover:border-sky-400">
                  {(item.thumbs?.sm || item.thumb) && <img src={item.thumbs?.sm || item.thumb || ''} alt={item.title} className="h-28 w-full rounded-lg object-cover" />}
                  <div className="mt-2 text-sm font-semibold text-white">{item.title}</div>
                  <div className="text-xs text-gray-400">#{item.id}</div>
                </button>
              ))}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
