// The editor — URL `/`. Introspects the api's registered content types
// (`content.types`) and generates a form per type with @voltro/cms's
// `<ContentForm>`; lists a type's drafts live (`content.list`), saves them
// (`content.saveDraft`, with per-field validation surfaced inline), and
// publishes / unpublishes them. One page, no dynamic routes — the selected type
// and the row being edited are component state.
import type { ReactNode } from 'react'
import { useEffect, useMemo, useState, type FormEvent } from 'react'
import type { PageMeta } from '@voltro/web'
import { useAction, useMutation, useSubscription } from '@voltro/client'
import { ContentForm } from '@voltro/cms/web'
import { T, useT } from '@voltro/i18n'
import { getCatalog } from '../../locales'
import {
  toContentFormType,
  type ContentRow,
  type ContentTypeDescriptor,
  type SaveResult,
} from '../../lib/api'

export const renderMode = 'ssr' as const

export const meta = ({ locale }: { readonly locale: string }): PageMeta => ({
  title: getCatalog(locale)['meta.editor.title'],
})

interface Violation { readonly field: string; readonly rule: string; readonly message: string }

export default function Editor(): ReactNode {
  const types = useAction<Record<string, never>, { types: ReadonlyArray<ContentTypeDescriptor> }>(
    'cms', 'content.types',
  )
  const getOne = useAction<{ type: string; id: string; status: string }, { row: Record<string, unknown> | null }>(
    'cms', 'content.get',
  )
  const save = useMutation<{ type: string; values: Record<string, unknown> }, SaveResult>('cms', 'content.saveDraft')
  const publish = useMutation<{ type: string; id: string }, { ok: boolean }>('cms', 'content.publish')
  const unpublish = useMutation<{ type: string; id: string }, { ok: boolean }>('cms', 'content.unpublish')

  const [typeList, setTypeList] = useState<ReadonlyArray<ContentTypeDescriptor>>([])
  const [active, setActive] = useState<string | null>(null)
  const [values, setValues] = useState<Record<string, unknown>>({})
  const [editingId, setEditingId] = useState<string | null>(null)
  const [violations, setViolations] = useState<ReadonlyArray<Violation>>([])
  const [saved, setSaved] = useState(false)

  // Load the content types once; select the first.
  useEffect(() => {
    void types.run({}).then((r) => {
      setTypeList(r.types)
      setActive((cur) => cur ?? r.types[0]?.name ?? null)
    })
  }, []) // mount-only fetch of the content-type descriptors

  const activeType = typeList.find((t) => t.name === active) ?? null

  // Live drafts of the active type. Memoised input so a stable object identity
  // avoids resubscribing every render; an unset/unknown type yields an empty list.
  const listInput = useMemo(() => ({ type: active ?? '—', status: 'draft' as const }), [active])
  const { data: rows } = useSubscription<ReadonlyArray<ContentRow>>('cms', 'content.list', listInput)
  const drafts = rows ?? []

  const resetForm = (): void => { setValues({}); setEditingId(null); setViolations([]) }

  const onSelectType = (name: string): void => { setActive(name); resetForm(); setSaved(false) }

  const onEdit = (id: string): void => {
    if (active === null) return
    void getOne.run({ type: active, id, status: 'draft' }).then((r) => {
      if (r.row) { setValues(r.row); setEditingId(id); setViolations([]); setSaved(false) }
    })
  }

  const onSubmit = (e: FormEvent): void => {
    e.preventDefault()
    if (active === null) return
    const payload = editingId ? { ...values, id: editingId } : values
    void save.mutate({ type: active, values: payload }).then((res) => {
      if (res.ok) { resetForm(); setSaved(true) } else { setViolations(res.violations); setSaved(false) }
    })
  }

  const onPublish = (id: string): void => { if (active) void publish.mutate({ type: active, id }) }
  const onUnpublish = (id: string): void => { if (active) void unpublish.mutate({ type: active, id }) }

  const statusKey = (s: string): 'editor.status.draft' | 'editor.status.published' | 'editor.status.archived' =>
    s === 'published' ? 'editor.status.published' : s === 'archived' ? 'editor.status.archived' : 'editor.status.draft'

  if (typeList.length === 0) {
    return <section className="cms-main"><p className="empty"><T id="editor.form.loading" /></p></section>
  }

  return (
    <div className="cms-grid">
      {/* Left: type chooser + live draft list */}
      <section className="cms-list">
        <h2 className="label"><T id="editor.types.heading" /></h2>
        <nav className="cms-types">
          {typeList.map((t) => (
            <button
              key={t.name} type="button"
              className={t.name === active ? 'chip active' : 'chip'}
              onClick={() => onSelectType(t.name)}
            >
              {t.displayName}
            </button>
          ))}
        </nav>

        <h3 className="label" style={{ marginTop: '1rem' }}>
          <T id="editor.list.heading" values={{ type: activeType?.pluralName ?? '' }} />
        </h3>
        {drafts.length === 0 ? (
          <p className="empty"><T id="editor.list.empty" /></p>
        ) : (
          <ul className="rows">
            {drafts.map((row) => (
              <li key={row.id}>
                <span className="grow">{row.title ?? row.slug ?? row.id}</span>
                <span className="tag"><T id={statusKey(row.status)} /></span>
                <button type="button" className="link" onClick={() => onEdit(row.id)}><T id="editor.row.edit" /></button>
                <button type="button" className="link" onClick={() => onPublish(row.id)}><T id="editor.row.publish" /></button>
                <button type="button" className="link" onClick={() => onUnpublish(row.id)}><T id="editor.row.unpublish" /></button>
              </li>
            ))}
          </ul>
        )}
      </section>

      {/* Right: the auto-generated form */}
      <section className="cms-editor">
        <h2>
          {editingId
            ? <T id="editor.form.editing" />
            : <T id="editor.form.new" values={{ type: activeType?.displayName ?? '' }} />}
        </h2>
        {activeType ? (
          <form onSubmit={onSubmit}>
            <ContentForm contentType={toContentFormType(activeType)} value={values} onChange={setValues} />
            {violations.length > 0 ? (
              <ul className="violations" role="alert">
                {violations.map((v) => <li key={v.field + v.rule}>{v.field}: {v.message}</li>)}
              </ul>
            ) : null}
            {saved ? <p className="ok"><T id="editor.form.saved" /></p> : null}
            <div className="row" style={{ marginTop: '0.75rem' }}>
              <button type="submit" className="btn" disabled={save.pending}>
                <T id={save.pending ? 'editor.form.saving' : 'editor.form.save'} />
              </button>
              {editingId ? (
                <button type="button" className="btn ghost" onClick={resetForm}><T id="editor.form.cancel" /></button>
              ) : null}
            </div>
          </form>
        ) : null}
      </section>
    </div>
  )
}
