// `/` — the notes page. Auto-mapped from src/pages/index.tsx by the
// framework's file-convention page discovery.
//
// THIS is the reactive end-to-end loop. `useSubscription('notes.list')`
// opens a live WebSocket subscription to the api's `notes.list` query;
// `useMutation('notes.create')` invokes the `notes.create` mutation. When the
// mutation commits, the server pushes a delta and this list re-renders — no
// refetch, no polling.
//
// Both come from `src/lib/api.ts`, which binds them ONCE to this api's
// generated procedure map — so the tag autocompletes, a typo is a compile
// error, and the row type is inferred rather than declared here.
//
// Auto-optimistic: `notes.create` declares `target: { table: 'notes', op:
// 'insert' }` server-side, so the framework prepends an optimistic row to
// this subscription the instant you submit — and replaces it with the real
// row (or reverts it) when the rpc resolves. There is no `.withOptimistic`,
// no `useOptimistic`, no `startTransition` — just `create.mutate(input)`.

import { useState, type FormEvent, type ReactNode } from 'react'
import type { PageMeta } from '@voltro/web'
import { T, useTFn } from '@voltro/i18n'
import { getCatalog } from '../locales'
import { useMutation, useSubscription } from '../lib/api'

// Locale-aware tab title: @voltro/web resolves meta({ locale }) from the
// active locale (the `voltro:locale` cookie in this cookie-i18n app).
export const meta = ({ locale }: { readonly locale: string }): PageMeta => ({
  title: getCatalog(locale)['meta.notes.title'],
})

// The dev AuthMiddleware resolves the tenant from the `x-tenant` header,
// defaulting to 'acme'. The `notes` table carries the `tenant()` mixin, so
// reads are auto-scoped to this tenant and `notes.create` guards that the
// submitted tenantId matches the caller's (a typed TenantMismatch otherwise).
const TENANT = 'acme'

const IndexPage = (): ReactNode => {
  // No row `interface` and no `<T>`: the shape comes from `notes.list`'s own
  // output schema, including the client's `optimistic` marker.
  const { data, revision, emittedAt, error, pendingPatches } =
    useSubscription('notes.list')

  const create = useMutation('notes.create')
  const t = useTFn()

  const notes = data ?? []
  const [title, setTitle] = useState('')
  const [body, setBody] = useState('')

  const handleSubmit = async (event: FormEvent) => {
    event.preventDefault()
    const trimmedTitle = title.trim()
    if (trimmedTitle.length === 0) return
    setTitle('')
    setBody('')
    try {
      await create.mutate({ tenantId: TENANT, title: trimmedTitle, body: body.trim() })
    } catch (mutationError) {
      // notes.create can fail with a typed TenantMismatch; surface it however
      // your UI prefers. The optimistic row auto-reverts on failure.
      console.error('notes.create failed:', mutationError)
    }
  }

  return (
    <section>
      <h1 style={{ fontSize: 24, marginBottom: 4 }}><T id="notes.heading" /></h1>
      <p style={{ color: '#666', marginTop: 0, fontSize: 13 }}>
        <T
          id="notes.status.tenant"
          values={{ tenant: TENANT, revision, code: (c: ReactNode) => <code>{c}</code> }}
        />
        {emittedAt ? (
          <T id="notes.status.delta" values={{ time: new Date(emittedAt).toLocaleTimeString() }} />
        ) : null}
        {pendingPatches > 0 && <T id="notes.status.pending" values={{ count: pendingPatches }} />}
        {data === undefined && error === undefined && <T id="notes.status.loading" />}
      </p>

      {error !== undefined && (
        <p style={{ color: '#c00', fontSize: 13 }}>
          <T id="notes.error" values={{ error: String(error) }} />
        </p>
      )}

      <form onSubmit={handleSubmit} style={{ display: 'grid', gap: 8, margin: '16px 0' }}>
        <input
          value={title}
          onChange={(event) => setTitle(event.target.value)}
          placeholder={t('notes.field.title')}
          style={{ padding: '6px 10px', fontSize: 14 }}
        />
        <textarea
          value={body}
          onChange={(event) => setBody(event.target.value)}
          placeholder={t('notes.field.body')}
          rows={2}
          style={{ padding: '6px 10px', fontSize: 14, resize: 'vertical' }}
        />
        <button type="submit" disabled={title.trim().length === 0 || create.pending} style={{ justifySelf: 'start' }}>
          {create.pending ? t('notes.adding') : t('notes.add')}
        </button>
      </form>

      {notes.length === 0 && data !== undefined && (
        <p style={{ color: '#999' }}><T id="notes.empty" /></p>
      )}

      <ul style={{ listStyle: 'none', padding: 0, margin: 0, display: 'grid', gap: 8 }}>
        {notes.map((note) => (
          <li
            key={note.id}
            style={{
              border: '1px solid #eee',
              borderRadius: 6,
              padding: '10px 12px',
              // Optimistic rows (not yet confirmed by the server) render faintly.
              opacity: note.optimistic ? 0.5 : 1,
              fontStyle: note.optimistic ? 'italic' : 'normal',
            }}
          >
            <strong>{note.title}</strong>
            {note.body && <p style={{ margin: '4px 0 0', color: '#444', fontSize: 14 }}>{note.body}</p>}
          </li>
        ))}
      </ul>
    </section>
  )
}

export default IndexPage
