import { useState, useEffect, useCallback, useRef } from 'react'
import { useEditor, EditorContent } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import Underline from '@tiptap/extension-underline'
import TextStyle from '@tiptap/extension-text-style'
import FontFamily from '@tiptap/extension-font-family'
import { Color } from '@tiptap/extension-color'
import Highlight from '@tiptap/extension-highlight'
import TextAlign from '@tiptap/extension-text-align'
import Image from '@tiptap/extension-image'
import Link from '@tiptap/extension-link'
import Table from '@tiptap/extension-table'
import TableRow from '@tiptap/extension-table-row'
import TableCell from '@tiptap/extension-table-cell'
import TableHeader from '@tiptap/extension-table-header'
import CharacterCount from '@tiptap/extension-character-count'
import Placeholder from '@tiptap/extension-placeholder'
import { marked } from 'marked'

import { FontSize } from './extensions/FontSize'
import { Video } from './extensions/Video'
import { Header } from './components/Header'
import { Toolbar } from './components/Toolbar'
import { Sidebar } from './components/Sidebar'
import { MediaModal } from './components/MediaModal'
import { api } from './api'

/* ── Route params ── */
const _parts = window.location.pathname.split('/')
const ARTICLE_ID = _parts[_parts.length - 1]
const TOKEN = new URLSearchParams(window.location.search).get('t') || ''
const IS_NEW = ARTICLE_ID === 'new'

const FONTS = [
  'Arimo', 'Caladea', 'Cormorant Garamond', 'Cousine', 'Crimson Text',
  'EB Garamond', 'Fira Code', 'Inter', 'JetBrains Mono', 'Josefin Sans',
  'Lato', 'Libre Baskerville', 'Libre Franklin', 'Lora', 'Merriweather',
  'Nunito', 'Open Sans', 'Oswald', 'Outfit', 'Patrick Hand',
  'Playfair Display', 'Poppins', 'Roboto Mono', 'Roboto', 'Source Code Pro',
  'Tinos',
]

const DEFAULT_META = {
  id: null,
  title: '',
  slug: '',
  excerpt: '',
  cover_url: null,
  source_url: null,
  font_family: 'Merriweather',
  category_id: null,
  tag_names: [],
  status: 'draft',
}

export default function App() {
  const [meta, setMeta] = useState(DEFAULT_META)
  const [categories, setCategories] = useState([])
  const [saveStatus, setSaveStatus] = useState('saved')
  const [mediaState, setMediaState] = useState(null)
  const [htmlMode, setHtmlMode]     = useState(false)
  const [htmlDraft, setHtmlDraft]   = useState('')
  const [rawHtml, setRawHtml]       = useState(null) // полный HTML-документ, обходит TipTap
  const rawHtmlRef = useRef(null)
  rawHtmlRef.current = rawHtml

  /* Refs so callbacks always see latest values without re-creating them */
  const metaRef = useRef(meta)
  metaRef.current = meta
  const currentIdRef = useRef(IS_NEW ? null : ARTICLE_ID)
  const saveTimerRef = useRef(null)
  const editorRef = useRef(null)   // always points to live editor instance
  const articleLoadedRef = useRef(false)
  const doSaveRef = useRef(null)   // always points to latest doSave

  /* ── Editor ── */
  const editor = useEditor({
    extensions: [
      StarterKit,
      Underline,
      TextStyle,
      FontFamily.configure({ types: ['textStyle'] }),
      FontSize,
      Color,
      Highlight.configure({ multicolor: true }),
      TextAlign.configure({ types: ['heading', 'paragraph', 'image'] }),
      Image.configure({ allowBase64: false }),
      Video,
      Link.configure({ openOnClick: false, HTMLAttributes: { target: '_blank', rel: 'noopener noreferrer' } }),
      Table.configure({ resizable: true }),
      TableRow,
      TableCell,
      TableHeader,
      Placeholder.configure({ placeholder: 'Начните писать статью…' }),
      CharacterCount,
    ],
    onUpdate: () => {
      setSaveStatus('unsaved')
      clearTimeout(saveTimerRef.current)
      // Always call the latest doSave via ref — avoids stale closure
      saveTimerRef.current = setTimeout(() => doSaveRef.current?.(), 3000)
    },
  })

  // Keep editorRef current every render so doSave never uses a stale instance
  editorRef.current = editor

  /* ── Load categories once on mount ── */
  useEffect(() => {
    api.getCategories(TOKEN).then(setCategories).catch(() => {})
  }, [])

  /* ── Load article once the editor is ready ── */
  useEffect(() => {
    if (!editor || IS_NEW || articleLoadedRef.current) return
    articleLoadedRef.current = true

    api.getArticle(ARTICLE_ID, TOKEN)
      .then(data => {
        setMeta({
          id: data.id,
          title: data.title,
          slug: data.slug,
          excerpt: data.excerpt || '',
          cover_url: data.cover_url || null,
          source_url: data.source_url || null,
          font_family: data.font_family || 'Merriweather',
          category_id: data.category?.id || null,
          tag_names: (data.tags || []).map(t => t.name),
          status: data.status,
        })
        const html = data.content?.startsWith('<')
          ? data.content
          : marked.parse(data.content || '')
        const isFullDoc = /^\s*<!DOCTYPE|^\s*<html/i.test(html)
        if (isFullDoc) {
          setRawHtml(html)
          editor.commands.setContent('', false)
        } else {
          setRawHtml(null)
          editor.commands.setContent(html, false)
        }
        setSaveStatus('saved')
      })
      .catch(() => {})
  }, [editor])

  /* ── Save ─────────────────────────────────────────────────────────────────
     Uses editorRef + metaRef so this callback is stable (no deps that change).
     doSaveRef is updated every render so the auto-save timer always calls the
     freshest version.
  ── */
  const doSave = useCallback(async overrideStatus => {
    const editor = editorRef.current
    if (!editor) return
    const m = metaRef.current
    setSaveStatus('saving')

    const payload = {
      title: m.title || 'Без названия',
      slug: m.slug || undefined,
      content: rawHtmlRef.current ?? editor.getHTML(),
      excerpt: m.excerpt,
      cover_url: m.cover_url || null,
      source_url: m.source_url || null,
      font_family: m.font_family,
      category_id: m.category_id || null,
      tag_names: m.tag_names,
      status: overrideStatus ?? m.status,
    }

    try {
      let saved
      if (!currentIdRef.current) {
        saved = await api.createArticle(payload, TOKEN)
        currentIdRef.current = saved.id
        setMeta(m => ({ ...m, id: saved.id, slug: saved.slug }))
        window.history.replaceState(null, '', `/editor/${saved.id}?t=${TOKEN}`)
      } else {
        saved = await api.updateArticle(currentIdRef.current, payload, TOKEN)
      }
      setSaveStatus('saved')
      if (overrideStatus) {
        setMeta(m => ({ ...m, status: overrideStatus }))
      }
    } catch {
      setSaveStatus('error')
    }
  }, []) // stable: reads from editorRef + metaRef

  // Keep ref current so the auto-save timer always calls the latest version
  doSaveRef.current = doSave

  const handleUploadCover = async file => {
    try {
      const res = await api.uploadMedia(file, TOKEN)
      setMeta(m => ({ ...m, cover_url: res.url }))
    } catch {}
  }

  /* ── Render ── */
  return (
    <div className="flex flex-col h-screen overflow-hidden bg-slate-50" style={{ fontFamily: 'Inter, sans-serif' }}>

      <Header
        saveStatus={saveStatus}
        articleStatus={meta.status}
        onSave={() => doSave()}
        onPublish={() => doSave('published')}
      />

      <div className="flex flex-1 overflow-hidden">

        {/* Editor column */}
        <div className="flex flex-col flex-1 min-w-0 bg-white">
          <Toolbar
            editor={editor}
            onInsertImage={() => setMediaState({
              type: 'image',
              cb: url => editor.chain().focus().setImage({ src: url }).run(),
            })}
            onInsertVideo={() => setMediaState({
              type: 'video',
              cb: url => editor.chain().focus().insertVideo({ src: url }).run(),
            })}
            onEditHtml={() => {
              if (htmlMode) {
                const isFullDoc = /^\s*<!DOCTYPE|^\s*<html/i.test(htmlDraft)
                if (isFullDoc) {
                  // Полный HTML-документ — обходим TipTap, сохраняем как есть
                  setRawHtml(htmlDraft)
                  editor.commands.setContent('', false)
                } else {
                  // Фрагмент — отдаём в TipTap
                  setRawHtml(null)
                  editor.commands.setContent(htmlDraft, true)
                }
                setHtmlMode(false)
              } else {
                // Открываем редактор: показываем rawHtml или HTML из TipTap
                setHtmlDraft(rawHtml ?? editor.getHTML())
                setHtmlMode(true)
              }
            }}
            htmlMode={htmlMode}
            fonts={FONTS}
          />

          <div className="flex-1 overflow-y-auto">
            <div className="max-w-[720px] mx-auto px-10 py-10">

              {/* Title */}
              <input
                className="w-full text-[2.2rem] font-bold text-slate-900 border-none outline-none bg-transparent placeholder-slate-300 mb-8 leading-tight"
                style={{ fontFamily: meta.font_family }}
                placeholder="Заголовок статьи"
                value={meta.title}
                onChange={e => setMeta(m => ({ ...m, title: e.target.value }))}
              />

              {/* HTML source textarea */}
              {htmlMode && (
                <textarea
                  spellCheck={false}
                  value={htmlDraft}
                  onChange={e => setHtmlDraft(e.target.value)}
                  style={{
                    width: '100%', minHeight: '60vh',
                    fontFamily: '"JetBrains Mono", "Fira Code", monospace',
                    fontSize: '0.8rem', lineHeight: 1.7,
                    color: '#1e293b', background: '#f8fafc',
                    border: '1px solid #e2e8f0', borderRadius: 8,
                    padding: '1rem', resize: 'vertical', outline: 'none',
                  }}
                />
              )}

              {/* TipTap visual editor */}
              {!htmlMode && !rawHtml && (
                <div style={{ fontFamily: meta.font_family }}>
                  <EditorContent editor={editor} />
                </div>
              )}

            </div>

            {/* Full HTML iframe — вне узкого контейнера, на всю ширину колонки */}
            {!htmlMode && rawHtml && (
              <iframe
                srcDoc={rawHtml}
                style={{ width: '100%', border: 'none', display: 'block' }}
                title="HTML preview"
                sandbox="allow-scripts allow-same-origin"
                onLoad={e => {
                  const doc = e.target.contentDocument
                  if (doc) e.target.style.height = doc.documentElement.scrollHeight + 'px'
                }}
              />
            )}
          </div>
        </div>

        {/* Sidebar */}
        <Sidebar
          meta={meta}
          categories={categories}
          onChange={updates => setMeta(m => ({ ...m, ...updates }))}
          onUploadCover={handleUploadCover}
          wordCount={editor?.storage.characterCount?.words() ?? 0}
          charCount={editor?.storage.characterCount?.characters() ?? 0}
          fonts={FONTS}
        />

      </div>

      {/* Media picker modal */}
      {mediaState && (
        <MediaModal
          type={mediaState.type}
          token={TOKEN}
          onSelect={url => { mediaState.cb(url); setMediaState(null) }}
          onClose={() => setMediaState(null)}
        />
      )}

    </div>
  )
}
