import { useEffect, useRef, useState } from 'react'
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import Link from '@tiptap/extension-link'
import Image from '@tiptap/extension-image'
import TextAlign from '@tiptap/extension-text-align'
import { api } from '../api/client.js'

// Toolbar button.
function Btn({ onClick, active, disabled, title, children }) {
  return (
    <button
      type="button"
      title={title}
      onMouseDown={(e) => e.preventDefault()} // keep editor selection
      onClick={onClick}
      disabled={disabled}
      className={`rte-btn${active ? ' is-active' : ''}`}
    >
      {children}
    </button>
  )
}

function escapeHtml(s) {
  return String(s).replace(/[&<>"]/g, (c) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' })[c])
}

// Alignment glyph: three lines justified to the given side.
function AlignIcon({ align }) {
  const rows = {
    left: [[2, 14], [2, 10], [2, 12]],
    center: [[2, 14], [4, 12], [3, 13]],
    right: [[2, 14], [6, 14], [4, 14]],
  }[align]
  return (
    <svg width="15" height="15" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" aria-hidden="true">
      {rows.map(([x1, x2], i) => (
        <line key={`${x1}-${x2}`} x1={x1} y1={4 + i * 4} x2={x2} y2={4 + i * 4} />
      ))}
    </svg>
  )
}

// Toolbar variants:
//   'full'    — every control, incl. the internal wiki-page link picker (wiki use).
//   'post'    — full minus the wiki-page picker (no page-list context in posts).
//   'minimal' — image upload only; text formatting stripped (Screenshots captions).
export default function RichTextEditor({ value, onChange, pages = [], variant = 'full' }) {
  const showText = variant !== 'minimal' // bold/italic/strike, headings, lists, quotes, links
  const showWikiLink = variant === 'full' && pages.length > 0
  const fileRef = useRef(null)
  const [uploading, setUploading] = useState(false)
  const [linkMenu, setLinkMenu] = useState(false)
  const [linkFilter, setLinkFilter] = useState('')

  const editor = useEditor({
    extensions: [
      StarterKit.configure({ heading: { levels: [2, 3] } }),
      Link.configure({ openOnClick: false, autolink: true }),
      Image.configure({ inline: false }),
      // Alignment stored as `text-align` on the block node (heading/paragraph),
      // so it round-trips through save/reload as inline style. Shared here means
      // every consumer — post editor, and the future rich_text / two_column
      // blocks — gets it for free.
      TextAlign.configure({ types: ['heading', 'paragraph'] }),
    ],
    content: value || '',
    onUpdate: ({ editor }) => onChange(editor.getHTML()),
  })

  // Safety net: sync if the parent resets `value` externally (won't fire during
  // normal typing because the parent value equals what the editor just emitted).
  useEffect(() => {
    if (!editor) return
    if (value != null && value !== editor.getHTML()) {
      editor.commands.setContent(value, false)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [value, editor])

  if (!editor) return null

  function setLink() {
    const prev = editor.getAttributes('link').href || ''
    const url = window.prompt('Link URL (leave blank to remove)', prev)
    if (url === null) return
    if (url === '') return editor.chain().focus().extendMarkRange('link').unsetLink().run()
    editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run()
  }

  function insertInternalLink(page) {
    const { from, to } = editor.state.selection
    if (from === to) {
      editor.chain().focus().insertContent(`<a href="/wiki/${page.slug}">${escapeHtml(page.title)}</a> `).run()
    } else {
      editor.chain().focus().extendMarkRange('link').setLink({ href: `/wiki/${page.slug}` }).run()
    }
    setLinkMenu(false)
    setLinkFilter('')
  }

  async function onPickImage(e) {
    const file = e.target.files?.[0]
    e.target.value = '' // allow re-selecting the same file
    if (!file) return
    setUploading(true)
    try {
      const { url } = await api.admin.upload(file)
      editor.chain().focus().setImage({ src: url, alt: file.name }).run()
    } catch (err) {
      alert(err.message || 'Image upload failed.')
    } finally {
      setUploading(false)
    }
  }

  return (
    <div className="rte">
      <div className="rte-toolbar">
        {showText && (
          <>
            <Btn title="Bold" active={editor.isActive('bold')} onClick={() => editor.chain().focus().toggleBold().run()}>
              <b>B</b>
            </Btn>
            <Btn title="Italic" active={editor.isActive('italic')} onClick={() => editor.chain().focus().toggleItalic().run()}>
              <i>I</i>
            </Btn>
            <Btn title="Strikethrough" active={editor.isActive('strike')} onClick={() => editor.chain().focus().toggleStrike().run()}>
              <s>S</s>
            </Btn>
            <span className="rte-sep" />
            <Btn title="Heading 2 (table of contents)" active={editor.isActive('heading', { level: 2 })} onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}>
              H2
            </Btn>
            <Btn title="Heading 3" active={editor.isActive('heading', { level: 3 })} onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}>
              H3
            </Btn>
            <span className="rte-sep" />
            <Btn title="Bullet list" active={editor.isActive('bulletList')} onClick={() => editor.chain().focus().toggleBulletList().run()}>
              • List
            </Btn>
            <Btn title="Numbered list" active={editor.isActive('orderedList')} onClick={() => editor.chain().focus().toggleOrderedList().run()}>
              1. List
            </Btn>
            <Btn title="Quote" active={editor.isActive('blockquote')} onClick={() => editor.chain().focus().toggleBlockquote().run()}>
              ❝
            </Btn>
            <Btn title="Code block" active={editor.isActive('codeBlock')} onClick={() => editor.chain().focus().toggleCodeBlock().run()}>
              {'</>'}
            </Btn>
            <Btn title="Divider" onClick={() => editor.chain().focus().setHorizontalRule().run()}>
              —
            </Btn>
            <span className="rte-sep" />
            <Btn title="Align left" active={editor.isActive({ textAlign: 'left' })} onClick={() => editor.chain().focus().setTextAlign('left').run()}>
              <AlignIcon align="left" />
            </Btn>
            <Btn title="Align center" active={editor.isActive({ textAlign: 'center' })} onClick={() => editor.chain().focus().setTextAlign('center').run()}>
              <AlignIcon align="center" />
            </Btn>
            <Btn title="Align right" active={editor.isActive({ textAlign: 'right' })} onClick={() => editor.chain().focus().setTextAlign('right').run()}>
              <AlignIcon align="right" />
            </Btn>
            <span className="rte-sep" />
            <Btn title="Link" active={editor.isActive('link')} onClick={setLink}>
              🔗
            </Btn>
            {showWikiLink && (
              <Btn title="Link to another wiki page" onClick={() => setLinkMenu((v) => !v)}>
                📄
              </Btn>
            )}
          </>
        )}
        <Btn title="Insert image" disabled={uploading} onClick={() => fileRef.current?.click()}>
          {uploading ? '…' : '🖼'}
        </Btn>
        <span className="rte-sep" />
        <Btn title="Undo" disabled={!editor.can().undo()} onClick={() => editor.chain().focus().undo().run()}>
          ↶
        </Btn>
        <Btn title="Redo" disabled={!editor.can().redo()} onClick={() => editor.chain().focus().redo().run()}>
          ↷
        </Btn>
      </div>

      {linkMenu && (
        <div className="rte-linkmenu">
          <input
            autoFocus
            className="input"
            placeholder="Filter pages…"
            value={linkFilter}
            onChange={(e) => setLinkFilter(e.target.value)}
          />
          <div className="rte-linkmenu-list">
            {pages
              .filter((p) => {
                const q = linkFilter.trim().toLowerCase()
                return !q || p.title.toLowerCase().includes(q) || p.slug.includes(q)
              })
              .slice(0, 30)
              .map((p) => (
                <button key={p.slug} type="button" className="rte-linkmenu-item" onClick={() => insertInternalLink(p)}>
                  <span>{p.title}</span>
                  <span className="rte-linkmenu-slug">/{p.slug}</span>
                </button>
              ))}
          </div>
        </div>
      )}

      <EditorContent editor={editor} className="rte-content prose" />
      <input ref={fileRef} type="file" accept="image/*" onChange={onPickImage} hidden />
    </div>
  )
}
