/*
 * M18 공통코드 관리 (SCR-A3 · §5B). CommonCodeController 실배선.
 * 정본: GET /api/common/code-groups(인증) · GET /api/common/codes/{grp}(인증) · POST /api/admin/codes/groups · POST /api/admin/codes ·
 *       DELETE /api/admin/codes/groups/{grp} · DELETE /api/admin/codes/{grp}/{code} (ADMIN).
 * UI: 좌 그룹 목록(선택·추가), 우 코드 값 테이블(추가/수정/삭제 모달). 저장은 upsert(코드 존재 시 갱신).
 */
import { useEffect, useMemo, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import { EmptyState, ErrorState, Skeleton } from '../../components/ui/States';
import { Button } from '../../components/ui/Button';
import { KxDataTable, type KxColumn } from '../../components/KxDataTable';
import { IconPlus } from '../../components/ui/icons';
import { errMessage, useToast } from '../work/workShared';
import { codeApi, type Code, type CodeGroup } from './adminCrudApi';
import './admin-modules.css';

export function CommonCodeAdminPage() {
  const { t } = useTranslation();
  const qc = useQueryClient();
  const { show, node: toast } = useToast();

  const groupsQ = useQuery({ queryKey: ['admin-code-groups'], queryFn: codeApi.groups, retry: false });
  const [selected, setSelected] = useState<string | null>(null);
  const [groupModal, setGroupModal] = useState<CodeGroup | null | undefined>(undefined);
  const [codeModal, setCodeModal] = useState<Code | null | undefined>(undefined);

  const groups = groupsQ.data ?? [];
  useEffect(() => {
    if (!selected && groups.length > 0) setSelected(groups[0].grpCode);
  }, [groups, selected]);

  const activeGroup = groups.find((g) => g.grpCode === selected) ?? null;

  const codesQ = useQuery({
    queryKey: ['admin-codes', selected],
    queryFn: () => codeApi.codes(selected as string),
    enabled: !!selected,
    retry: false,
  });

  const saveGroupM = useMutation({
    mutationFn: (g: CodeGroup) => codeApi.saveGroup(g),
    onSuccess: (_d, g) => {
      show(t('code.groupSaved'));
      setGroupModal(undefined);
      setSelected(g.grpCode);
      qc.invalidateQueries({ queryKey: ['admin-code-groups'] });
    },
    onError: (e) => show(errMessage(e)),
  });
  const delGroupM = useMutation({
    mutationFn: (grpCode: string) => codeApi.removeGroup(grpCode),
    onSuccess: () => {
      show(t('code.groupDeleted'));
      setSelected(null);
      qc.invalidateQueries({ queryKey: ['admin-code-groups'] });
    },
    onError: (e) => show(errMessage(e)),
  });
  const saveCodeM = useMutation({
    mutationFn: (c: Code) => codeApi.saveCode(c),
    onSuccess: () => {
      show(t('code.codeSaved'));
      setCodeModal(undefined);
      qc.invalidateQueries({ queryKey: ['admin-codes', selected] });
    },
    onError: (e) => show(errMessage(e)),
  });
  const delCodeM = useMutation({
    mutationFn: ({ grpCode, code }: { grpCode: string; code: string }) => codeApi.removeCode(grpCode, code),
    onSuccess: () => {
      show(t('code.codeDeleted'));
      qc.invalidateQueries({ queryKey: ['admin-codes', selected] });
    },
    onError: (e) => show(errMessage(e)),
  });

  const codes = codesQ.data ?? [];

  // 코드 값 테이블 컬럼 — 검색·정렬·페이지·CSV 는 KxDataTable 담당(관리 열은 정렬/검색/CSV 제외).
  const codeColumns = useMemo<KxColumn<Code>[]>(
    () => [
      { key: 'code', header: t('code.code'), value: (c) => c.code,
        render: (c) => <span className="kx-adm-mono">{c.code}</span> },
      { key: 'name', header: t('code.name'), value: (c) => c.codeName,
        render: (c) => <span className="kx-adm-tbl__strong">{c.codeName}</span> },
      { key: 'value', header: t('code.value'), value: (c) => c.codeValue ?? '',
        render: (c) => <span className="kx-adm-muted">{c.codeValue ?? '—'}</span> },
      { key: 'sort', header: t('code.sort'), numeric: true, value: (c) => c.sortOrder },
      { key: 'use', header: t('code.use'), value: (c) => (c.useYn === 'N' ? t('code.unused') : t('code.used')),
        render: (c) => (
          <span className={`kx-adm-pill kx-adm-pill--${c.useYn === 'N' ? 'neutral' : 'success'}`}>
            {c.useYn === 'N' ? t('code.unused') : t('code.used')}
          </span>
        ) },
      { key: 'manage', header: t('code.manage'), csv: false, sortable: false, searchable: false,
        thClassName: 'kx-adm-col-manage', tdClassName: 'kx-adm-col-manage',
        render: (c) => (
          <div className="kx-adm-tbl__actions">
            <Button variant="ghost" onClick={() => setCodeModal(c)}>{t('code.edit')}</Button>
            <Button
              variant="ghost"
              className="kx-adm-del"
              disabled={delCodeM.isPending}
              onClick={() => {
                if (window.confirm(t('code.deleteCodeConfirm', { name: c.codeName })))
                  delCodeM.mutate({ grpCode: c.grpCode, code: c.code });
              }}
            >
              {t('code.delete')}
            </Button>
          </div>
        ) },
    ],
    [t, delCodeM.isPending, delCodeM],
  );

  return (
    <div className="kx-page kx-adm">
      <header className="kx-adm__head">
        <div>
          <h1 className="kx-adm__title">{t('code.title')}</h1>
          <p className="kx-adm__subtitle">{t('code.subtitle')}</p>
        </div>
        <Button leadingIcon={<IconPlus size={16} />} onClick={() => setGroupModal(null)}>{t('code.addGroup')}</Button>
      </header>

      {groupsQ.isLoading && <Skeleton height={320} radius={12} />}
      {groupsQ.isError && !groupsQ.isLoading && (
        <ErrorState message={t('code.groupLoadError')} onRetry={() => groupsQ.refetch()} />
      )}

      {!groupsQ.isLoading && !groupsQ.isError && (
        groups.length === 0 ? (
          <EmptyState title={t('code.noGroupsTitle')} description={t('code.noGroupsDesc')} />
        ) : (
          <div className="kx-adm-codes">
            {/* 좌: 그룹 */}
            <section className="kx-card kx-adm-codes__groups" aria-label={t('code.codeGroup')}>
              <div className="kx-adm-codes__head">
                <h2>{t('code.codeGroup')}</h2>
              </div>
              <ul className="kx-adm-glist">
                {groups.map((g) => (
                  <li key={g.grpCode}>
                    <button
                      type="button"
                      className={`kx-adm-gitem ${g.grpCode === selected ? 'is-active' : ''}`}
                      onClick={() => setSelected(g.grpCode)}
                    >
                      <span className="kx-adm-gitem__name">{g.grpName}</span>
                      <span className="kx-adm-gitem__code">{g.grpCode}{g.useYn === 'N' ? ` · ${t('code.unused')}` : ''}</span>
                    </button>
                  </li>
                ))}
              </ul>
            </section>

            {/* 우: 코드 값 */}
            <section className="kx-card kx-adm-codes__values" aria-label={t('code.codeValues')}>
              <div className="kx-adm-codes__head">
                <div>
                  <h2>{t('code.valuesOf', { name: activeGroup?.grpName ?? t('code.code') })}</h2>
                  {activeGroup?.description && <p className="kx-adm-muted">{activeGroup.description}</p>}
                </div>
                <div className="kx-adm-tbl__actions">
                  {activeGroup && (
                    <>
                      <Button variant="ghost" onClick={() => setGroupModal(activeGroup)}>{t('code.editGroup')}</Button>
                      <Button
                        variant="ghost"
                        className="kx-adm-del"
                        disabled={delGroupM.isPending}
                        onClick={() => {
                          if (window.confirm(t('code.deleteGroupConfirm', { name: activeGroup.grpName })))
                            delGroupM.mutate(activeGroup.grpCode);
                        }}
                      >
                        {t('code.deleteGroup')}
                      </Button>
                      <Button leadingIcon={<IconPlus size={16} />} onClick={() => setCodeModal(null)}>{t('code.addCode')}</Button>
                    </>
                  )}
                </div>
              </div>

              {codesQ.isLoading && <div style={{ padding: 16 }}><Skeleton height={160} radius={8} /></div>}
              {codesQ.isError && !codesQ.isLoading && (
                <div style={{ padding: 16 }}>
                  <ErrorState message={t('code.codeLoadError')} onRetry={() => codesQ.refetch()} />
                </div>
              )}
              {!codesQ.isLoading && !codesQ.isError && (
                <div className="kx-adm-codes__tbl">
                  <KxDataTable
                    columns={codeColumns}
                    rows={codes}
                    rowKey={(c) => c.code}
                    csvFileName={`codes_${selected ?? 'group'}`}
                    ariaLabel={t('code.codeValues')}
                    emptyTitle={t('code.noCodesTitle')}
                    emptyDescription={t('code.noCodesDesc')}
                  />
                </div>
              )}
            </section>
          </div>
        )
      )}

      {groupModal !== undefined && (
        <GroupModal
          group={groupModal}
          existingCodes={groups.map((g) => g.grpCode)}
          saving={saveGroupM.isPending}
          onClose={() => setGroupModal(undefined)}
          onSubmit={(g) => saveGroupM.mutate(g)}
        />
      )}
      {codeModal !== undefined && activeGroup && (
        <CodeModal
          grpCode={activeGroup.grpCode}
          code={codeModal}
          existingCodes={codes.map((c) => c.code)}
          saving={saveCodeM.isPending}
          onClose={() => setCodeModal(undefined)}
          onSubmit={(c) => saveCodeM.mutate(c)}
        />
      )}
      {toast}
    </div>
  );
}

function GroupModal({
  group,
  existingCodes,
  saving,
  onClose,
  onSubmit,
}: {
  group: CodeGroup | null;
  existingCodes: string[];
  saving: boolean;
  onClose: () => void;
  onSubmit: (g: CodeGroup) => void;
}) {
  const { t } = useTranslation();
  const isNew = group === null;
  const [grpCode, setGrpCode] = useState(group?.grpCode ?? '');
  const [grpName, setGrpName] = useState(group?.grpName ?? '');
  const [description, setDescription] = useState(group?.description ?? '');
  const [useYn, setUseYn] = useState(group?.useYn ?? 'Y');
  const [sortOrder, setSortOrder] = useState(String(group?.sortOrder ?? 0));
  const [error, setError] = useState<string | null>(null);

  function submit(e: React.FormEvent) {
    e.preventDefault();
    setError(null);
    if (!grpCode.trim() || !grpName.trim()) {
      setError(t('code.errGroupRequired'));
      return;
    }
    if (isNew && existingCodes.includes(grpCode.trim())) {
      setError(t('code.errDupGroup'));
      return;
    }
    onSubmit({
      grpCode: grpCode.trim(),
      grpName: grpName.trim(),
      description: description.trim() || null,
      useYn,
      sortOrder: Number(sortOrder) || 0,
    });
  }

  return (
    <div className="kx-adm-modal" role="dialog" aria-modal="true" aria-labelledby="group-modal-title">
      <div className="kx-adm-modal__backdrop" onClick={onClose} />
      <form className="kx-adm-modal__panel" onSubmit={submit}>
        <h2 id="group-modal-title" className="kx-adm-modal__title">{isNew ? t('code.addGroup') : t('code.editGroup')}</h2>
        <div className="kx-adm-modal__grid">
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('code.groupCode')}</span>
            <input className="kx-adm-field__input kx-adm-mono" value={grpCode} disabled={!isNew} onChange={(e) => setGrpCode(e.target.value)} />
          </label>
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('code.groupName')}</span>
            <input className="kx-adm-field__input" value={grpName} onChange={(e) => setGrpName(e.target.value)} />
          </label>
          <label className="kx-adm-field kx-adm-field--full">
            <span className="kx-adm-field__label">{t('code.description')}</span>
            <input className="kx-adm-field__input" value={description} onChange={(e) => setDescription(e.target.value)} />
          </label>
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('code.sort')}</span>
            <input className="kx-adm-field__input" type="number" value={sortOrder} onChange={(e) => setSortOrder(e.target.value)} />
          </label>
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('code.useYn')}</span>
            <select className="kx-adm-field__select" value={useYn} onChange={(e) => setUseYn(e.target.value)}>
              <option value="Y">{t('code.used')}</option>
              <option value="N">{t('code.unused')}</option>
            </select>
          </label>
        </div>
        {error && <p className="kx-adm-modal__error" role="alert">{error}</p>}
        <div className="kx-adm-modal__actions">
          <Button variant="ghost" type="button" onClick={onClose}>{t('code.cancel')}</Button>
          <Button type="submit" disabled={saving}>{saving ? t('code.saving') : t('code.save')}</Button>
        </div>
      </form>
    </div>
  );
}

function CodeModal({
  grpCode,
  code,
  existingCodes,
  saving,
  onClose,
  onSubmit,
}: {
  grpCode: string;
  code: Code | null;
  existingCodes: string[];
  saving: boolean;
  onClose: () => void;
  onSubmit: (c: Code) => void;
}) {
  const { t } = useTranslation();
  const isNew = code === null;
  const [codeVal, setCodeVal] = useState(code?.code ?? '');
  const [codeName, setCodeName] = useState(code?.codeName ?? '');
  const [codeValue, setCodeValue] = useState(code?.codeValue ?? '');
  const [attr1, setAttr1] = useState(code?.attr1 ?? '');
  const [sortOrder, setSortOrder] = useState(String(code?.sortOrder ?? 0));
  const [useYn, setUseYn] = useState(code?.useYn ?? 'Y');
  const [error, setError] = useState<string | null>(null);

  function submit(e: React.FormEvent) {
    e.preventDefault();
    setError(null);
    if (!codeVal.trim() || !codeName.trim()) {
      setError(t('code.errCodeRequired'));
      return;
    }
    if (isNew && existingCodes.includes(codeVal.trim())) {
      setError(t('code.errDupCode'));
      return;
    }
    onSubmit({
      grpCode,
      code: codeVal.trim(),
      codeName: codeName.trim(),
      codeValue: codeValue.trim() || null,
      sortOrder: Number(sortOrder) || 0,
      useYn,
      attr1: attr1.trim() || null,
    });
  }

  return (
    <div className="kx-adm-modal" role="dialog" aria-modal="true" aria-labelledby="code-modal-title">
      <div className="kx-adm-modal__backdrop" onClick={onClose} />
      <form className="kx-adm-modal__panel" onSubmit={submit}>
        <h2 id="code-modal-title" className="kx-adm-modal__title">{isNew ? t('code.addCode') : t('code.editCode')}</h2>
        <p className="kx-adm-modal__desc">{t('code.group')} <span className="kx-adm-mono">{grpCode}</span></p>
        <div className="kx-adm-modal__grid">
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('code.codeReq')}</span>
            <input className="kx-adm-field__input kx-adm-mono" value={codeVal} disabled={!isNew} onChange={(e) => setCodeVal(e.target.value)} />
          </label>
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('code.nameReq')}</span>
            <input className="kx-adm-field__input" value={codeName} onChange={(e) => setCodeName(e.target.value)} />
          </label>
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('code.value')}</span>
            <input className="kx-adm-field__input" value={codeValue} onChange={(e) => setCodeValue(e.target.value)} />
          </label>
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('code.attr1')}</span>
            <input className="kx-adm-field__input" value={attr1} onChange={(e) => setAttr1(e.target.value)} />
          </label>
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('code.sort')}</span>
            <input className="kx-adm-field__input" type="number" value={sortOrder} onChange={(e) => setSortOrder(e.target.value)} />
          </label>
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('code.useYn')}</span>
            <select className="kx-adm-field__select" value={useYn} onChange={(e) => setUseYn(e.target.value)}>
              <option value="Y">{t('code.used')}</option>
              <option value="N">{t('code.unused')}</option>
            </select>
          </label>
        </div>
        {error && <p className="kx-adm-modal__error" role="alert">{error}</p>}
        <div className="kx-adm-modal__actions">
          <Button variant="ghost" type="button" onClick={onClose}>{t('code.cancel')}</Button>
          <Button type="submit" disabled={saving}>{saving ? t('code.saving') : t('code.save')}</Button>
        </div>
      </form>
    </div>
  );
}
