// 제네릭 CRUD 페이지 — 목록/검색/추가/수정/삭제 공통. 각 도메인 페이지에서 columns + form 스펙만 정의.
import { useState, type ReactNode } from 'react'
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
import { PageHeader, Toolbar, Table, Modal, Button, Field, TextInput, Select, type Column } from './ui'

export interface FormFieldSpec {
  key: string
  label: string
  type?: 'text' | 'number' | 'select' | 'textarea' | 'checkbox' | 'date' | 'time' | 'datetime-local'
  opts?: string[] | { value: string; label: string }[]
  placeholder?: string
  required?: boolean
}

interface CrudProps<T extends Record<string, any>> {
  title: string
  subtitle?: string
  addLabel?: string
  queryKey: any[]
  fetcher: () => Promise<T[]>
  onCreate?: (d: any) => Promise<any>
  onUpdate?: (id: number, d: any) => Promise<any>
  onDelete?: (id: number) => Promise<any>
  columns: Column<T>[]
  form?: FormFieldSpec[]
  defaults?: Record<string, any>
  toolbarExtra?: ReactNode
  rowActions?: (row: T) => ReactNode
  readOnly?: boolean
}

export function CrudPage<T extends Record<string, any>>(p: CrudProps<T>) {
  const qc = useQueryClient()
  const [modal, setModal] = useState<any | null>(null)
  const { data: rows = [], isLoading } = useQuery({ queryKey: p.queryKey, queryFn: p.fetcher })

  const saveMut = useMutation({
    mutationFn: (d: any) => (d.id && p.onUpdate ? p.onUpdate(d.id, d) : p.onCreate!(d)),
    onSuccess: () => { qc.invalidateQueries({ queryKey: [p.queryKey[0]] }); setModal(null) },
  })
  const delMut = useMutation({
    mutationFn: (id: number) => p.onDelete!(id),
    onSuccess: () => qc.invalidateQueries({ queryKey: [p.queryKey[0]] }),
  })

  const columns: Column<T>[] = [...p.columns]
  if (!p.readOnly && (p.form || p.rowActions)) {
    columns.push({
      key: '__act', header: '', align: 'right',
      render: (row: any) => (
        <div className="flex gap-2 justify-end">
          {p.rowActions?.(row)}
          {p.form && p.onUpdate && (
            <button onClick={() => setModal(row)} className="text-brand hover:text-blue-300" title="수정">
              <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M4 20h4l10-10-4-4L4 16v4z"/><path d="M13.5 6.5l4 4"/></svg>
            </button>
          )}
          {p.onDelete && (
            <button onClick={() => { if (confirm('삭제하시겠습니까?')) delMut.mutate(row.id) }} className="text-red-400 hover:text-red-300" title="삭제">
              <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13"/></svg>
            </button>
          )}
        </div>
      ),
    })
  }

  return (
    <div>
      <PageHeader title={p.title} subtitle={p.subtitle}
        actions={!p.readOnly && p.form && p.onCreate && (
          <Button icon="plus" onClick={() => setModal({ ...(p.defaults || {}) })}>{p.addLabel || '추가'}</Button>
        )} />
      {p.toolbarExtra && <Toolbar>{p.toolbarExtra}</Toolbar>}
      {isLoading ? <div className="p-8 text-center text-gray-400 text-sm">로딩 중...</div>
        : <Table columns={columns} rows={rows as T[]} rowKey={(r: any) => r.id} />}

      {modal && p.form && (
        <Modal title={modal.id ? '수정' : (p.addLabel || '추가')} onClose={() => setModal(null)}>
          <CrudForm spec={p.form} initial={modal} onSave={d => saveMut.mutate(d)} saving={saveMut.isPending} />
        </Modal>
      )}
    </div>
  )
}

export function CrudForm({ spec, initial, onSave, saving }: {
  spec: FormFieldSpec[]; initial: any; onSave: (d: any) => void; saving?: boolean
}) {
  const init: any = { id: initial.id }
  spec.forEach(f => {
    init[f.key] = initial[f.key] ?? (f.type === 'checkbox' ? true : f.type === 'number' ? '' : '')
  })
  const [f, setF] = useState<any>(init)
  const set = (k: string, v: any) => setF((p: any) => ({ ...p, [k]: v }))

  return (
    <form onSubmit={e => { e.preventDefault(); onSave(f) }}>
      {spec.map(fs => (
        <Field key={fs.key} label={fs.label}>
          {fs.type === 'select' ? (
            <Select className="w-full" value={String(f[fs.key] ?? '')} onChange={v => set(fs.key, v)}>
              <option value="">선택</option>
              {(fs.opts || []).map(o => {
                const val = typeof o === 'string' ? o : o.value
                const lab = typeof o === 'string' ? o : o.label
                return <option key={val} value={val}>{lab}</option>
              })}
            </Select>
          ) : fs.type === 'textarea' ? (
            <textarea value={f[fs.key] ?? ''} onChange={e => set(fs.key, e.target.value)} rows={4}
              placeholder={fs.placeholder}
              className="w-full bg-ink border border-edge rounded px-3 py-2 text-sm text-white font-mono outline-none focus:border-brand" />
          ) : fs.type === 'checkbox' ? (
            <label className="flex items-center gap-2 text-sm text-gray-300">
              <input type="checkbox" checked={!!f[fs.key]} onChange={e => set(fs.key, e.target.checked)} />
              활성
            </label>
          ) : (
            <TextInput className="w-full"
              type={fs.type === 'number' ? 'number' : (fs.type === 'date' || fs.type === 'time' || fs.type === 'datetime-local') ? fs.type : 'text'}
              value={String(f[fs.key] ?? '')} onChange={v => set(fs.key, fs.type === 'number' ? (v === '' ? '' : Number(v)) : v)}
              placeholder={fs.placeholder} />
          )}
        </Field>
      ))}
      <button type="submit" disabled={saving}
        className="w-full bg-brand hover:bg-brand2 text-white py-2 rounded text-sm font-medium disabled:opacity-50 mt-1">
        {saving ? '저장 중...' : '저장'}
      </button>
    </form>
  )
}
