import { useCallback, useEffect, useMemo, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import Modal from '../../../components/Modal.jsx'
import { Loading } from '../../../components/PageState.jsx'
import { api } from '../../../api/client.js'
import '../../../blocks/index.js' // registers all block types
import { listBlocks, getBlock, makeBlockId } from '../../../blocks/registry.js'
import { SelectField, TextField, TextAreaField } from '../../../blocks/editorKit.jsx'

const LAYOUTS = [
  ['default', 'Default'],
  ['full_width', 'Full width'],
  ['landing', 'Landing'],
]
const NAV_GROUPS = [
  ['', 'None'],
  ['main', 'Main nav'],
  ['footer', 'Footer'],
  ['account', 'Account'],
  ['hidden', 'Hidden'],
]

const EMPTY = {
  title: '',
  slug: '',
  status: 'draft',
  blocks: [],
  metadata: { seoTitle: '', metaDescription: '', ogImage: '', canonicalUrl: '', robots: '' },
  settings: { layout: 'default', showInNav: false, navGroup: '', navOrder: null, protected: false },
}

// Map an API page (grouped shape) into local editable form state.
function toForm(page) {
  return {
    title: page.title || '',
    slug: page.slug || '',
    status: page.status || 'draft',
    blocks: Array.isArray(page.blocks) ? page.blocks : [],
    metadata: { ...EMPTY.metadata, ...cleanNulls(page.metadata) },
    settings: {
      layout: page.settings?.layout || 'default',
      showInNav: Boolean(page.settings?.showInNav),
      navGroup: page.settings?.navGroup || '',
      navOrder: page.settings?.navOrder ?? null,
      protected: Boolean(page.settings?.protected),
    },
  }
}

function cleanNulls(obj) {
  const out = {}
  for (const [k, v] of Object.entries(obj || {})) out[k] = v == null ? '' : v
  return out
}

export default function PageBuilder() {
  const { id } = useParams()
  const isEdit = Boolean(id)
  const navigate = useNavigate()

  const [form, setForm] = useState(EMPTY)
  const [protectedNow, setProtectedNow] = useState(false) // server truth, edit mode
  const [loading, setLoading] = useState(isEdit)
  const [busy, setBusy] = useState(false)
  const [error, setError] = useState('')
  const [details, setDetails] = useState([]) // block validation errors
  const [notice, setNotice] = useState('')
  const [tab, setTab] = useState('content')
  const [pwModal, setPwModal] = useState(false)
  const [dragIndex, setDragIndex] = useState(null)

  const palette = useMemo(() => listBlocks(), [])

  useEffect(() => {
    if (!isEdit) return
    let active = true
    setLoading(true)
    api.admin
      .getPage(id)
      .then((page) => {
        if (!active) return
        setForm(toForm(page))
        setProtectedNow(Boolean(page.settings?.protected))
        setLoading(false)
      })
      .catch((err) => {
        if (!active) return
        setError(err.message || 'Could not load the page.')
        setLoading(false)
      })
    return () => {
      active = false
    }
  }, [id, isEdit])

  // ── Block operations ────────────────────────────────────────────────
  const addBlock = useCallback((type) => {
    const def = getBlock(type)
    if (!def) return
    const block = { id: makeBlockId(), type, version: def.version, visible: true, props: def.defaults() }
    setForm((f) => ({ ...f, blocks: [...f.blocks, block] }))
  }, [])

  const updateBlock = useCallback((blockId, nextProps) => {
    setForm((f) => ({
      ...f,
      blocks: f.blocks.map((b) => (b.id === blockId ? { ...b, props: nextProps } : b)),
    }))
  }, [])

  const toggleVisible = useCallback((blockId) => {
    setForm((f) => ({
      ...f,
      blocks: f.blocks.map((b) => (b.id === blockId ? { ...b, visible: b.visible === false } : b)),
    }))
  }, [])

  const removeBlock = useCallback((blockId) => {
    setForm((f) => ({ ...f, blocks: f.blocks.filter((b) => b.id !== blockId) }))
  }, [])

  const moveBlock = useCallback((from, to) => {
    setForm((f) => {
      if (to < 0 || to >= f.blocks.length) return f
      const next = [...f.blocks]
      const [moved] = next.splice(from, 1)
      next.splice(to, 0, moved)
      return { ...f, blocks: next }
    })
  }, [])

  function onDrop(index) {
    if (dragIndex === null || dragIndex === index) return setDragIndex(null)
    moveBlock(dragIndex, index)
    setDragIndex(null)
  }

  // ── Form field setters ──────────────────────────────────────────────
  const setField = (k) => (v) => setForm((f) => ({ ...f, [k]: v }))
  const setMeta = (k) => (v) => setForm((f) => ({ ...f, metadata: { ...f.metadata, [k]: v } }))
  const setSetting = (k) => (v) => setForm((f) => ({ ...f, settings: { ...f.settings, [k]: v } }))

  // Serialize local state into an API payload. Empty metadata strings become
  // null; navGroup '' becomes null.
  function payload() {
    const metadata = {}
    for (const [k, v] of Object.entries(form.metadata)) metadata[k] = v === '' ? null : v
    const settings = {
      layout: form.settings.layout,
      showInNav: Boolean(form.settings.showInNav),
      navGroup: form.settings.navGroup === '' ? null : form.settings.navGroup,
      navOrder: form.settings.navOrder === '' || form.settings.navOrder == null ? null : Number(form.settings.navOrder),
    }
    return { title: form.title.trim(), status: form.status, blocks: form.blocks, metadata, settings }
  }

  async function save({ silent } = {}) {
    setBusy(true)
    setError('')
    setDetails([])
    setNotice('')
    try {
      if (isEdit) {
        await api.admin.updatePage(id, payload())
        if (!silent) setNotice('Saved.')
      } else {
        if (!form.slug.trim()) throw new Error('A slug is required.')
        const created = await api.admin.createPage({ slug: form.slug.trim(), ...payload() })
        navigate(`/admin/pages/${created.id}`, { replace: true })
      }
    } catch (err) {
      setError(err.message || 'Could not save the page.')
      if (err.body?.details) setDetails(err.body.details)
    } finally {
      setBusy(false)
    }
  }

  async function togglePublish() {
    const next = form.status === 'published' ? 'draft' : 'published'
    setForm((f) => ({ ...f, status: next }))
    // Persist immediately (edit mode) so the status change isn't lost.
    if (isEdit) {
      setBusy(true)
      setError('')
      try {
        await api.admin.updatePage(id, { ...payload(), status: next })
        setNotice(next === 'published' ? 'Published.' : 'Unpublished.')
      } catch (err) {
        setError(err.message || 'Could not change status.')
      } finally {
        setBusy(false)
      }
    }
  }

  async function protectPage() {
    setBusy(true)
    setError('')
    try {
      await api.admin.updatePage(id, { settings: { protected: true } })
      setProtectedNow(true)
      setForm((f) => ({ ...f, settings: { ...f.settings, protected: true } }))
      setNotice('Page protected.')
    } catch (err) {
      setError(err.message || 'Could not protect the page.')
    } finally {
      setBusy(false)
    }
  }

  async function unprotectPage(password) {
    setBusy(true)
    setError('')
    try {
      await api.admin.unprotectPage(id, password)
      setProtectedNow(false)
      setForm((f) => ({ ...f, settings: { ...f.settings, protected: false } }))
      setPwModal(false)
      setNotice('Protection removed.')
    } catch (err) {
      setError(err.message || 'Could not unprotect the page.')
    } finally {
      setBusy(false)
    }
  }

  async function preview() {
    setError('')
    try {
      const { token } = await api.admin.createPagePreview(id)
      window.open(`/preview/${id}/${token}`, '_blank', 'noopener')
    } catch (err) {
      setError(err.message || 'Could not create a preview link.')
    }
  }

  async function remove() {
    if (!confirm('Delete this page? This cannot be undone.')) return
    setBusy(true)
    setError('')
    try {
      await api.admin.deletePage(id)
      navigate('/admin/pages')
    } catch (err) {
      setError(err.message || 'Could not delete the page.')
      setBusy(false)
    }
  }

  if (loading) return <Loading />

  const published = form.status === 'published'

  return (
    <section>
      {/* Toolbar */}
      <div className="pb-toolbar">
        <button className="pill" onClick={() => navigate('/admin/pages')}>← Pages</button>
        <span className={`badge ${published ? 'badge-pub' : 'badge-draft'}`}>{published ? 'Published' : 'Draft'}</span>
        <div style={{ flex: 1 }} />
        {isEdit && (
          <button className="pill" onClick={preview} disabled={busy}>Preview</button>
        )}
        {isEdit && (
          <button className="pill" onClick={togglePublish} disabled={busy}>
            {published ? 'Unpublish' : 'Publish'}
          </button>
        )}
        <button className="btn btn-primary btn-sq" onClick={() => save()} disabled={busy}>
          {busy ? 'Saving…' : isEdit ? 'Save' : 'Create'}
        </button>
      </div>

      {error && (
        <div className="pb-error sans">
          {error}
          {details.length > 0 && (
            <ul style={{ margin: '6px 0 0', paddingLeft: 18 }}>
              {details.map((d, i) => <li key={i}>{d}</li>)}
            </ul>
          )}
        </div>
      )}
      {notice && <div className="pb-notice sans">{notice}</div>}

      {/* Title + slug */}
      <div style={{ display: 'flex', gap: 14, flexWrap: 'wrap', margin: '16px 0' }}>
        <label style={{ flex: '2 1 320px' }}>
          <span className="field-label">Title</span>
          <input className="input" value={form.title} onChange={(e) => setField('title')(e.target.value)} />
        </label>
        <label style={{ flex: '1 1 220px' }}>
          <span className="field-label">Slug {isEdit && '(fixed)'}</span>
          <input
            className="input"
            value={form.slug}
            disabled={isEdit}
            placeholder="my-page"
            onChange={(e) => setField('slug')(e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, ''))}
          />
        </label>
      </div>

      {/* Tabs */}
      <div className="pb-tabs">
        <button className={`pb-tab ${tab === 'content' ? 'is-active' : ''}`} onClick={() => setTab('content')}>Content</button>
        <button className={`pb-tab ${tab === 'settings' ? 'is-active' : ''}`} onClick={() => setTab('settings')}>Settings &amp; SEO</button>
      </div>

      {tab === 'content' && (
        <>
          <div className="pb-palette">
            <span className="field-label" style={{ margin: '0 6px 0 0' }}>Add block</span>
            {palette.map((b) => (
              <button key={b.type} className="pill" onClick={() => addBlock(b.type)} disabled={busy}>
                <span aria-hidden style={{ marginRight: 6 }}>{b.icon}</span>{b.label}
              </button>
            ))}
          </div>

          <div className="pb-canvas">
            {form.blocks.length === 0 && (
              <p className="sans dim" style={{ textAlign: 'center', padding: 30 }}>
                No blocks yet — add one from the palette above.
              </p>
            )}
            {form.blocks.map((block, i) => {
              const def = getBlock(block.type)
              const Editor = def?.editor
              const hidden = block.visible === false
              return (
                <div
                  key={block.id}
                  className={`pb-block-card ${hidden ? 'is-hidden' : ''} ${dragIndex === i ? 'is-dragging' : ''}`}
                  draggable
                  onDragStart={() => setDragIndex(i)}
                  onDragOver={(e) => e.preventDefault()}
                  onDrop={() => onDrop(i)}
                  onDragEnd={() => setDragIndex(null)}
                >
                  <div className="pb-block-head">
                    <span className="pb-drag" title="Drag to reorder">⠿</span>
                    <strong className="sans">{def?.label || block.type}</strong>
                    <div style={{ flex: 1 }} />
                    <button className="pill pb-mini" title={hidden ? 'Show' : 'Hide'} onClick={() => toggleVisible(block.id)}>
                      {hidden ? '🙈' : '👁'}
                    </button>
                    <button className="pill pb-mini" disabled={i === 0} onClick={() => moveBlock(i, i - 1)} title="Move up">↑</button>
                    <button className="pill pb-mini" disabled={i === form.blocks.length - 1} onClick={() => moveBlock(i, i + 1)} title="Move down">↓</button>
                    <button className="pill pb-mini" onClick={() => removeBlock(block.id)} title="Remove">✕</button>
                  </div>
                  <div className="pb-block-body">
                    {Editor ? (
                      <Editor props={block.props || {}} onChange={(p) => updateBlock(block.id, p)} />
                    ) : (
                      <p className="sans dim">Unknown block type: {block.type}</p>
                    )}
                  </div>
                </div>
              )
            })}
          </div>
        </>
      )}

      {tab === 'settings' && (
        <div className="pb-settings">
          <div className="card" style={{ padding: 18 }}>
            <p className="card-kicker">SEO &amp; metadata</p>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 12, marginTop: 12 }}>
              <TextField label="SEO title" value={form.metadata.seoTitle} maxLength={200} onChange={setMeta('seoTitle')} hint="Overrides the page title in the browser tab / search results." />
              <TextAreaField label="Meta description" value={form.metadata.metaDescription} rows={2} maxLength={400} onChange={setMeta('metaDescription')} />
              <TextField label="OG image URL" value={form.metadata.ogImage} maxLength={500} onChange={setMeta('ogImage')} />
              <TextField label="Canonical URL" value={form.metadata.canonicalUrl} maxLength={500} onChange={setMeta('canonicalUrl')} />
              <TextField label="Robots" value={form.metadata.robots} maxLength={100} onChange={setMeta('robots')} placeholder="index,follow" />
            </div>
          </div>

          <div className="card" style={{ padding: 18 }}>
            <p className="card-kicker">Layout &amp; navigation</p>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 12, marginTop: 12 }}>
              <SelectField label="Layout" value={form.settings.layout} onChange={setSetting('layout')} options={LAYOUTS} />
              <label style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <input type="checkbox" checked={form.settings.showInNav} onChange={(e) => setSetting('showInNav')(e.target.checked)} />
                <span className="sans" style={{ color: 'var(--muted)', fontSize: '0.9rem' }}>Show in navigation</span>
              </label>
              <SelectField label="Nav group" value={form.settings.navGroup} onChange={setSetting('navGroup')} options={NAV_GROUPS} />
              <TextField label="Nav order" value={form.settings.navOrder ?? ''} onChange={(v) => setSetting('navOrder')(v === '' ? null : v.replace(/[^0-9]/g, ''))} hint="Lower numbers appear first." />
            </div>
          </div>

          <div className="card" style={{ padding: 18 }}>
            <p className="card-kicker">Protection &amp; danger zone</p>
            <p className="sans dim" style={{ fontSize: '0.85rem', marginTop: 8 }}>
              A protected page can’t be deleted and its protection can only be removed by re-entering your password.
            </p>
            {!isEdit && <p className="sans dim" style={{ fontSize: '0.82rem' }}>Save the page first to manage protection.</p>}
            {isEdit && (
              <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', marginTop: 10 }}>
                {protectedNow ? (
                  <button className="pill" onClick={() => setPwModal(true)} disabled={busy}>🔓 Remove protection…</button>
                ) : (
                  <button className="pill" onClick={protectPage} disabled={busy}>🔒 Protect page</button>
                )}
                <button className="pill pb-danger" onClick={remove} disabled={busy || protectedNow} title={protectedNow ? 'Unprotect first' : 'Delete'}>
                  Delete page
                </button>
              </div>
            )}
          </div>
        </div>
      )}

      {pwModal && (
        <UnprotectModal onCancel={() => setPwModal(false)} onConfirm={unprotectPage} busy={busy} error={error} />
      )}
    </section>
  )
}

function UnprotectModal({ onCancel, onConfirm, busy, error }) {
  const [pw, setPw] = useState('')
  return (
    <Modal
      title="Confirm your password"
      onClose={onCancel}
      width={420}
      footer={
        <>
          <button className="pill" onClick={onCancel} disabled={busy}>Cancel</button>
          <button className="btn btn-primary btn-sq" onClick={() => onConfirm(pw)} disabled={busy || !pw}>
            {busy ? 'Verifying…' : 'Remove protection'}
          </button>
        </>
      }
    >
      <p className="sans dim" style={{ marginTop: 0, fontSize: '0.88rem' }}>
        Removing protection is a sensitive change — re-enter your account password to continue.
      </p>
      <input
        type="password"
        className="input"
        autoFocus
        value={pw}
        onChange={(e) => setPw(e.target.value)}
        onKeyDown={(e) => e.key === 'Enter' && pw && onConfirm(pw)}
        placeholder="Password"
      />
      {error && <p className="sans" style={{ color: '#d98b84', fontSize: '0.85rem', marginBottom: 0 }}>{error}</p>}
    </Modal>
  )
}
