import { useCallback, useEffect, useRef, useState } from 'react'
import CodeMirrorEditor from './CodeMirrorEditor'
import Preview from './Preview'
import { encodeDocument, decodeDocument } from './url'
import sampleDoc from './sample.md?raw'
import './App.css'

function readHash(): string | null {
  const h = window.location.hash.replace(/^#/, '')
  if (!h) return null
  try {
    return decodeDocument(h)
  } catch {
    return null
  }
}

export default function App() {
  const [text, setText] = useState<string>(() => readHash() ?? sampleDoc)
  const [urlLength, setUrlLength] = useState<number>(() => window.location.href.length)
  const [copied, setCopied] = useState(false)

  // Debounced text -> URL. replaceState (not assignment) so typing doesn't
  // flood the browser history; lastWrittenRef lets the hashchange listener
  // tell our own writes apart from external navigation.
  const lastWrittenRef = useRef<string | null>(null)
  useEffect(() => {
    const t = setTimeout(() => {
      const encoded = text ? encodeDocument(text) : ''
      lastWrittenRef.current = encoded
      const url = new URL(window.location.href)
      url.hash = encoded
      window.history.replaceState(null, '', url)
      setUrlLength(url.href.length)
    }, 300)
    return () => clearTimeout(t)
  }, [text])

  // URL -> text, when the user pastes a different mdshare link into the
  // address bar or navigates back/forward.
  useEffect(() => {
    const onHashChange = () => {
      const h = window.location.hash.replace(/^#/, '')
      if (h === lastWrittenRef.current) return
      const decoded = readHash()
      if (decoded !== null) setText(decoded)
    }
    window.addEventListener('hashchange', onHashChange)
    return () => window.removeEventListener('hashchange', onHashChange)
  }, [])

  const copyLink = useCallback(async () => {
    // Encode the current text directly so a fast type-then-copy can't race
    // the debounced URL write.
    const url = new URL(window.location.href)
    url.hash = text ? encodeDocument(text) : ''
    lastWrittenRef.current = url.hash.replace(/^#/, '')
    window.history.replaceState(null, '', url)
    setUrlLength(url.href.length)
    await navigator.clipboard.writeText(url.href)
    setCopied(true)
    setTimeout(() => setCopied(false), 1500)
  }, [text])

  const newDocument = useCallback(() => {
    if (text.trim() && text !== sampleDoc) {
      if (!window.confirm('Discard the current document? (The old link keeps working.)')) return
    }
    setText('')
  }, [text])

  // Simple draggable splitter
  const [split, setSplit] = useState(0.5)
  const mainRef = useRef<HTMLDivElement>(null)
  const onSplitterDown = useCallback((e: React.PointerEvent) => {
    e.preventDefault()
    const main = mainRef.current
    if (!main) return
    const rect = main.getBoundingClientRect()
    const onMove = (ev: PointerEvent) => {
      const f = (ev.clientX - rect.left) / rect.width
      setSplit(Math.min(0.8, Math.max(0.2, f)))
    }
    const onUp = () => {
      window.removeEventListener('pointermove', onMove)
      window.removeEventListener('pointerup', onUp)
    }
    window.addEventListener('pointermove', onMove)
    window.addEventListener('pointerup', onUp)
  }, [])

  return (
    <div className="app">
      <header className="topbar">
        <span className="title">mdshare</span>
        <span className="subtitle">markdown that lives in the URL</span>
        <span className="spacer" />
        <span className="url-size" title="Length of the shareable URL">
          URL: {urlLength.toLocaleString()} chars
        </span>
        <button onClick={newDocument}>New</button>
        <button className="primary" onClick={copyLink}>
          {copied ? 'Copied!' : 'Copy link'}
        </button>
      </header>
      <main className="panes" ref={mainRef}>
        <section className="pane" style={{ flexBasis: `${split * 100}%` }}>
          <CodeMirrorEditor value={text} onChange={setText} />
        </section>
        <div className="splitter" onPointerDown={onSplitterDown} />
        <section className="pane pane-preview">
          <Preview markdown={text} />
        </section>
      </main>
    </div>
  )
}
