import { useState, useEffect, useRef, useCallback } from 'react';
import { EditorView, keymap, placeholder as cmPlaceholder } from '@codemirror/view';
import { EditorState, Compartment } from '@codemirror/state';
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
import { languages } from '@codemirror/language-data';
import { defaultKeymap, indentWithTab } from '@codemirror/commands';
import { vim } from '@replit/codemirror-vim';
import { search, searchKeymap } from '@codemirror/search';
import { closeBrackets } from '@codemirror/autocomplete';
import { renderMarkdown } from '../../../lib/markdown';
import { getPost, savePost, deletePost, getAssets, ApiError } from '../../../lib/api';
import type { Asset } from '../../../lib/types';
import AssetManager from './AssetManager';

interface Props {
  editSlug?: string;
}

const salonTheme = EditorView.theme({
  '&': {
    backgroundColor: 'var(--crust)',
    color: 'var(--text)',
    border: '1px solid var(--surface1)',
    borderRadius: '0.75rem',
    fontSize: '14px',
  },
  '.cm-content': {
    fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace',
    padding: '1rem',
    caretColor: 'var(--text)',
  },
  '.cm-cursor': { borderLeftColor: 'var(--text)' },
  '.cm-selectionBackground': { backgroundColor: 'var(--surface2) !important' },
  '&.cm-focused .cm-selectionBackground': { backgroundColor: 'var(--surface2) !important' },
  '.cm-activeLine': { backgroundColor: 'var(--surface0)' },
  '.cm-gutters': {
    backgroundColor: 'var(--mantle)',
    color: 'var(--overlay0)',
    border: 'none',
  },
  '.cm-activeLineGutter': { backgroundColor: 'var(--surface0)' },
  '.cm-panels': {
    backgroundColor: 'var(--mantle)',
    color: 'var(--text)',
    borderTop: '1px solid var(--surface1)',
  },
  '.cm-searchMatch': { backgroundColor: 'var(--yellow)', opacity: '0.3' },
  '.cm-searchMatch-selected': { backgroundColor: 'var(--peach)', opacity: '0.4' },
  '.cm-fat-cursor': {
    backgroundColor: 'var(--mauve) !important',
    color: 'var(--crust) !important',
  },
  '&:not(.cm-focused) .cm-fat-cursor': {
    outline: '1px solid var(--mauve)',
    backgroundColor: 'transparent !important',
  },
}, { dark: true });

// Compartment for hot-swapping vim mode without recreating the editor
const vimCompartment = new Compartment();

function clientSlugify(s: string): string {
  return s
    .toLowerCase()
    .normalize('NFD')
    .replace(/[̀-ͯ]/g, '')
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
}

export default function Editor({ editSlug }: Props) {
  const editorRef = useRef<HTMLDivElement>(null);
  const viewRef = useRef<EditorView | null>(null);
  const previewRef = useRef<HTMLDivElement>(null);
  const previewTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const updatePreviewRef = useRef<() => void>(() => {});
  const today = new Date().toISOString().slice(0, 10);
  const [title, setTitle] = useState('');
  const [slug, setSlug] = useState(editSlug || '');
  const [slugTouched, setSlugTouched] = useState(!!editSlug);
  const [date, setDate] = useState(today);
  const [summary, setSummary] = useState('');
  const [tagsInput, setTagsInput] = useState('');
  const [draft, setDraft] = useState(false);
  const [originalSlug, setOriginalSlug] = useState(editSlug || '');
  const [alert, setAlert] = useState<{ msg: string; type: 'success' | 'error' } | null>(null);
  const [showModal, setShowModal] = useState(false);
  const [showPreview, setShowPreview] = useState(false);
  const [mobileView, setMobileView] = useState<'edit' | 'preview'>('edit');
  const [vimEnabled, setVimEnabled] = useState(() =>
    typeof window !== 'undefined' && window.innerWidth > 768
  );
  const [showAutocomplete, setShowAutocomplete] = useState(false);
  const [autocompleteAssets, setAutocompleteAssets] = useState<Asset[]>([]);
  const [autocompletePos, setAutocompletePos] = useState({ top: 0, left: 0 });

  function showAlertMsg(msg: string, type: 'success' | 'error') {
    setAlert({ msg, type });
    window.scrollTo({ top: 0, behavior: 'smooth' });
    setTimeout(() => setAlert(null), 5000);
  }

  const updatePreview = useCallback(() => {
    if (!showPreview || !viewRef.current || !previewRef.current) return;
    const content = viewRef.current.state.doc.toString();
    previewRef.current.innerHTML = renderMarkdown(content);
  }, [showPreview]);

  useEffect(() => { updatePreviewRef.current = updatePreview; }, [updatePreview]);

  // Initialize CodeMirror once
  useEffect(() => {
    if (!editorRef.current || viewRef.current) return;

    const state = EditorState.create({
      doc: '',
      extensions: [
        vimCompartment.of(window.innerWidth > 768 ? vim() : []),
        keymap.of([...defaultKeymap, ...searchKeymap, indentWithTab]),
        search(),
        closeBrackets(),
        markdown({ base: markdownLanguage, codeLanguages: languages }),
        EditorView.lineWrapping,
        salonTheme,
        cmPlaceholder('# A title for the work\n\n![alt text](/uploads/your-image.jpg "optional caption")\n\nNotes, context, materials...'),
        EditorView.updateListener.of(update => {
          if (!update.docChanged) return;
          if (previewTimerRef.current) clearTimeout(previewTimerRef.current);
          previewTimerRef.current = setTimeout(() => updatePreviewRef.current(), 300);
          const pos = update.state.selection.main.head;
          const line = update.state.doc.lineAt(pos);
          const textBefore = line.text.slice(0, pos - line.from);
          const lastChar = textBefore.slice(-1);
          if (lastChar === '/' || lastChar === '!') {
            triggerAutocomplete(update.view);
          } else if (lastChar === ' ' || textBefore.length === 0) {
            setShowAutocomplete(false);
          }
        }),
      ],
    });

    const view = new EditorView({ state, parent: editorRef.current });
    viewRef.current = view;

    return () => { view.destroy(); viewRef.current = null; };
  }, []);

  // Hot-swap vim mode via compartment reconfiguration
  useEffect(() => {
    if (!viewRef.current) return;
    viewRef.current.dispatch({
      effects: vimCompartment.reconfigure(vimEnabled ? vim() : []),
    });
  }, [vimEnabled]);

  // Load existing post for editing
  useEffect(() => {
    if (!editSlug) return;
    getPost(editSlug).then(post => {
      if (post.title) setTitle(post.title);
      if (post.summary) setSummary(post.summary);
      if (post.date) setDate(post.date);
      if (post.tags?.length) setTagsInput(post.tags.join(', '));
      setDraft(!!post.draft);
      if (post.content && viewRef.current) {
        viewRef.current.dispatch({
          changes: { from: 0, to: viewRef.current.state.doc.length, insert: post.content },
        });
      }
    }).catch(() => showAlertMsg('Failed to load post.', 'error'));
  }, [editSlug]);

  // Auto-derive slug from title until user edits the slug field
  useEffect(() => {
    if (slugTouched) return;
    setSlug(clientSlugify(title));
  }, [title, slugTouched]);

  useEffect(() => {
    if (showPreview) updatePreview();
  }, [showPreview, updatePreview]);

  async function triggerAutocomplete(view: EditorView) {
    try {
      const assets = await getAssets();
      setAutocompleteAssets(assets.slice(0, 8));
      const pos = view.state.selection.main.head;
      const coords = view.coordsAtPos(pos);
      if (coords) {
        const editorRect = editorRef.current?.getBoundingClientRect();
        if (editorRect) {
          setAutocompletePos({
            top: coords.bottom - editorRect.top + 4,
            left: coords.left - editorRect.left,
          });
        }
      }
      setShowAutocomplete(true);
    } catch { /* ignore */ }
  }

  function insertAssetMarkdown(asset: Asset) {
    const view = viewRef.current;
    if (!view) return;
    const isImage = /\.(jpg|jpeg|png|webp|gif|svg)$/i.test(asset.name);
    const md = isImage ? `![${asset.name}](${asset.url})` : `[${asset.name}](${asset.url})`;

    const pos = view.state.selection.main.head;
    const line = view.state.doc.lineAt(pos);
    const textBefore = line.text.slice(0, pos - line.from);
    const triggerIdx = Math.max(textBefore.lastIndexOf('/'), textBefore.lastIndexOf('!'));

    if (triggerIdx !== -1) {
      const from = line.from + triggerIdx;
      view.dispatch({ changes: { from, to: pos, insert: md } });
    } else {
      view.dispatch({ changes: { from: pos, insert: md } });
    }
    view.focus();
    setShowAutocomplete(false);
  }

  function handleAssetSelect(asset: Asset) {
    insertAssetMarkdown(asset);
    setShowModal(false);
  }

  async function handleSave() {
    const content = viewRef.current?.state.doc.toString() || '';
    if (!title.trim() || !slug || !content) {
      showAlertMsg('Title, slug, and body are required.', 'error');
      return;
    }
    if (!/!\[[^\]]*\]\([^)]+\)/.test(content)) {
      showAlertMsg('A gallery work must include at least one image — insert via the Assets panel or type "!".', 'error');
      return;
    }
    const tags = tagsInput
      .split(',')
      .map(t => t.trim())
      .filter(Boolean);
    try {
      const saved = await savePost({
        slug,
        old_slug: originalSlug || null,
        title: title.trim(),
        date,
        summary: summary || null,
        tags,
        draft,
        content,
      });
      showAlertMsg('Post saved!', 'success');
      if (saved?.slug && saved.slug !== slug) {
        setSlug(saved.slug);
        setSlugTouched(true);
      }
      setOriginalSlug(saved?.slug ?? slug);
    } catch (e) {
      showAlertMsg(e instanceof ApiError ? `Error: ${e.message}` : 'Failed to connect to server.', 'error');
    }
  }

  async function handleDelete() {
    const target = originalSlug || slug;
    if (!confirm(`Remove work "${target}" from the catalogue permanently?`)) return;
    try {
      await deletePost(target);
      window.location.href = '/admin';
    } catch {
      showAlertMsg('Error deleting post.', 'error');
    }
  }

  useEffect(() => {
    if (!showAutocomplete) return;
    const handler = () => setShowAutocomplete(false);
    window.addEventListener('click', handler);
    return () => window.removeEventListener('click', handler);
  }, [showAutocomplete]);

  return (
    <>
      {alert && (
        <div className={`p-4 rounded-lg mb-6 text-sm font-semibold text-center backdrop-blur-sm shadow-lg ${
          alert.type === 'success' ? 'bg-green/15 border border-green/30' : 'bg-red/15 border border-red/30'
        }`} style={{ color: 'var(--text)' }}>
          {alert.msg}
        </div>
      )}

      {/* Actions bar */}
      <div className="flex flex-wrap gap-4 mb-6">
        {originalSlug && (
          <button onClick={handleDelete} className="text-red hover:bg-red/10 px-6 py-3 rounded-lg transition-colors font-bold border border-red/20">
            Delete
          </button>
        )}
        <button onClick={handleSave} className="bg-mauve text-rosewater font-bold py-3 px-8 rounded-lg hover:bg-red transition-all transform hover:scale-105 whitespace-nowrap">
          Save work
        </button>
        {originalSlug && (
          <a
            href={`/posts/${encodeURIComponent(originalSlug)}`}
            target="_blank"
            rel="noreferrer"
            className="bg-blue text-crust font-bold py-3 px-8 rounded-lg hover:bg-sky transition-all transform hover:scale-105 whitespace-nowrap inline-flex items-center justify-center gap-2"
          >
            <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
            View work
          </a>
        )}
      </div>

      <div className="space-y-6">
        {/* Title + Date */}
        <div className="grid grid-cols-1 md:grid-cols-[1fr_180px] gap-4">
          <div>
            <label className="field-label">Title</label>
            <input
              type="text"
              value={title}
              onChange={e => setTitle(e.target.value)}
              required
              placeholder="Untitled (charcoal on paper)"
              className="field-input"
            />
          </div>
          <div>
            <label className="field-label">Date</label>
            <input
              type="date"
              value={date}
              onChange={e => setDate(e.target.value)}
              className="field-input font-mono"
            />
          </div>
        </div>

        {/* Slug */}
        <div>
          <label className="field-label">
            Slug <span className="normal-case tracking-normal text-[var(--overlay0)] italic font-display">— auto-derived from title</span>
          </label>
          <input
            type="text"
            value={slug}
            onChange={e => { setSlug(e.target.value); setSlugTouched(true); }}
            required
            placeholder="untitled-charcoal-on-paper"
            className="field-input font-mono"
          />
        </div>

        {/* Tags + Draft */}
        <div className="grid grid-cols-1 md:grid-cols-[1fr_auto] gap-4 md:items-end">
          <div>
            <label className="field-label">Tags (comma-separated)</label>
            <input
              type="text"
              value={tagsInput}
              onChange={e => setTagsInput(e.target.value)}
              placeholder="oil, paper, 2026, study"
              className="field-input"
            />
          </div>
          <label className="flex items-center gap-2 px-4 py-3 bg-[var(--surface0)]/60 border border-[var(--surface2)] cursor-pointer hover:border-[var(--peach)] transition-colors select-none" style={{ borderRadius: 1 }}>
            <input
              type="checkbox"
              checked={draft}
              onChange={e => setDraft(e.target.checked)}
              className="accent-[var(--peach)]"
            />
            <span className="text-sm font-display italic text-[var(--subtext1)]">Sketch (draft)</span>
          </label>
        </div>

        {/* Summary */}
        <div>
          <label className="field-label">Caption (optional)</label>
          <textarea
            value={summary}
            onChange={e => setSummary(e.target.value)}
            rows={2}
            placeholder="A short caption for the catalogue index..."
            className="field-input resize-none"
          />
        </div>

        {/* Editor Toolbar */}
        <div className="flex flex-col md:flex-row justify-between items-start md:items-end gap-2">
          <div className="flex items-center gap-3">
            <label className="block text-sm font-medium text-subtext1 italic">Type '/' or '!' to insert an image · at least one image is required</label>
          </div>
          <div className="flex items-center gap-2">
            <button
              type="button"
              onClick={() => setVimEnabled(v => !v)}
              className={`text-xs px-3 py-1.5 rounded border transition-colors font-mono ${
                vimEnabled
                  ? 'bg-mauve/20 text-mauve border-mauve/30'
                  : 'bg-surface0 text-subtext0 border-surface1 hover:text-text'
              }`}
              title={vimEnabled ? 'Vim mode ON' : 'Vim mode OFF'}
            >
              {vimEnabled ? 'VIM' : 'vim'}
            </button>
            <button
              type="button"
              onClick={() => setShowPreview(p => !p)}
              className={`text-xs px-3 py-1.5 rounded border transition-colors ${
                showPreview
                  ? 'bg-blue/20 text-blue border-blue/30'
                  : 'bg-surface0 text-subtext0 border-surface1 hover:text-text'
              }`}
            >
              {showPreview ? 'Hide Preview' : 'Show Preview'}
            </button>
            <button
              type="button"
              onClick={() => setShowModal(true)}
              className="text-sm bg-surface0 hover:bg-surface1 text-lavender px-4 py-1.5 rounded border border-surface1 transition-colors inline-flex items-center gap-2"
            >
              <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>
              Assets
            </button>
          </div>
        </div>

        {/* Mobile-only Edit | Preview tab bar */}
        {showPreview && (
          <div className="md:hidden flex gap-2" role="tablist" aria-label="Editor view">
            <button
              type="button"
              role="tab"
              aria-selected={mobileView === 'edit'}
              onClick={() => setMobileView('edit')}
              className={`flex-1 text-xs px-3 py-2 rounded border transition-colors ${
                mobileView === 'edit'
                  ? 'bg-blue/20 text-blue border-blue/30'
                  : 'bg-surface0 text-subtext0 border-surface1 hover:text-text'
              }`}
            >
              Edit
            </button>
            <button
              type="button"
              role="tab"
              aria-selected={mobileView === 'preview'}
              onClick={() => setMobileView('preview')}
              className={`flex-1 text-xs px-3 py-2 rounded border transition-colors ${
                mobileView === 'preview'
                  ? 'bg-blue/20 text-blue border-blue/30'
                  : 'bg-surface0 text-subtext0 border-surface1 hover:text-text'
              }`}
            >
              Preview
            </button>
          </div>
        )}

        {/* Editor + Preview — desktop side-by-side, mobile single-pane via tabs */}
        <div className={`relative ${showPreview ? 'md:grid md:grid-cols-2 md:gap-4 md:items-stretch' : ''}`}>
          <div
            className={`relative min-h-[500px] md:flex md:flex-col ${
              showPreview && mobileView === 'preview' ? 'hidden' : ''
            }`}
          >
            <div ref={editorRef} className="min-h-[500px] md:flex-1 md:min-h-0" />

            {/* Autocomplete dropdown */}
            {showAutocomplete && autocompleteAssets.length > 0 && (
              <div
                className="absolute z-50 bg-mantle border border-surface1 rounded-lg shadow-2xl max-h-64 overflow-y-auto w-80"
                style={{ top: autocompletePos.top, left: autocompletePos.left }}
                onClick={e => e.stopPropagation()}
              >
                <div className="p-2 text-[10px] text-subtext0 uppercase border-b border-white/5 bg-crust/50">Assets Library</div>
                <ul className="py-1">
                  {autocompleteAssets.map(asset => {
                    const img = /\.(jpg|jpeg|png|webp|gif|svg)$/i.test(asset.name);
                    return (
                      <li
                        key={asset.name}
                        onClick={() => insertAssetMarkdown(asset)}
                        className="px-4 py-2 hover:bg-mauve/20 cursor-pointer text-sm truncate text-subtext1 hover:text-mauve flex items-center gap-3 transition-colors"
                      >
                        <div className="w-6 h-6 flex-shrink-0 bg-surface0 rounded flex items-center justify-center overflow-hidden">
                          {img ? (
                            <img src={asset.url} className="w-full h-full object-cover" alt="" />
                          ) : (
                            <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/></svg>
                          )}
                        </div>
                        <span className="truncate">{asset.name}</span>
                      </li>
                    );
                  })}
                </ul>
              </div>
            )}
          </div>

          {/* Live Preview — stretches to match editor height on desktop, full-pane via tabs on mobile */}
          {showPreview && (
            <div
              className={`border border-surface1 rounded-xl bg-crust/50 overflow-y-auto flex-col md:flex md:min-h-0 ${
                mobileView === 'preview' ? 'flex min-h-[60vh]' : 'hidden'
              }`}
            >
              <div className="sticky top-0 bg-mantle px-4 py-2 text-xs text-subtext0 uppercase border-b border-surface1 z-10">
                Preview
              </div>
              <div ref={previewRef} className="prose max-w-none p-4 md:p-6 flex-1" />
            </div>
          )}
        </div>
      </div>

      {/* Asset Modal */}
      {showModal && (
        <div className="fixed inset-0 z-[100] bg-crust/80 backdrop-blur-sm flex items-center justify-center p-4 md:p-6">
          <div className="glass w-full max-w-5xl max-h-[90vh] flex flex-col overflow-hidden">
            <header className="p-4 md:p-6 border-b border-white/5 flex justify-between items-center bg-surface0/20">
              <div>
                <h2 className="text-xl md:text-2xl font-bold text-mauve">Asset Library</h2>
                <p className="text-xs text-subtext0">Click 'Insert' to add an asset to your post.</p>
              </div>
              <button onClick={() => setShowModal(false)} className="p-2 text-subtext0 hover:text-red transition-colors">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18"/><path d="m6 6 12 12"/></svg>
              </button>
            </header>
            <div className="p-4 md:p-6 overflow-y-auto flex-1 bg-bg/50">
              <AssetManager mode="select" onSelect={handleAssetSelect} />
            </div>
          </div>
        </div>
      )}
    </>
  );
}
