/*
 * SCR-A5 감사로그 (M18 · §5B-1). Stitch scr_a5 이식 + 라이브 백엔드 실배선.
 * 정본: GET /api/admin/audit?action&actorId&eventId&page&size → PageResponse<AuditLogRow> (AuditLogController).
 * 보안: 백엔드 DTO에 IP/자격증명 원문 미포함 → IP 컬럼 미표시(포렌식·PII 무결성). summary 는 백엔드가 정제(민감정보 제거).
 * 상태 3종: 로딩 스켈레톤 / 빈 / 에러(재시도). 포렌식 무결성 원칙상 샘플 폴백을 두지 않는다.
 * CSV 내보내기: 현재 페이지 로드분만 클라이언트 생성(서버측 전량 export 엔드포인트는 미제공 — 갭).
 */
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Trans, useTranslation } from 'react-i18next';
import type { TFunction } from 'i18next';
import { EmptyState, ErrorState, Skeleton } from '../../components/ui/States';
import { Button } from '../../components/ui/Button';
import { IconDownload, IconSearch } from '../../components/ui/icons';
import { auditApi, KNOWN_AUDIT_ACTIONS, type AuditLogRow } from './adminModulesApi';
import './admin-modules.css';

const PAGE_SIZES = [20, 50, 100];

export function AuditLogPage() {
  const { t } = useTranslation();
  const [action, setAction] = useState('');
  const [actorId, setActorId] = useState('');
  const [eventId, setEventId] = useState('');
  const [size, setSize] = useState(50);
  const [page, setPage] = useState(0);
  // 실제 조회에 반영된 확정 필터(입력과 분리 — "필터 적용" 클릭 시 반영)
  const [applied, setApplied] = useState<{ action: string; actorId: string; eventId: string }>({
    action: '',
    actorId: '',
    eventId: '',
  });

  const q = useQuery({
    queryKey: ['admin-audit', applied, page, size],
    queryFn: () =>
      auditApi.search({
        action: applied.action || undefined,
        actorId: applied.actorId || undefined,
        eventId: applied.eventId || undefined,
        page,
        size,
      }),
    retry: false,
  });

  const rows = q.data?.items ?? [];
  const total = q.data?.total ?? 0;
  const totalPages = Math.max(1, Math.ceil(total / size));
  const from = total === 0 ? 0 : page * size + 1;
  const to = Math.min(total, (page + 1) * size);

  function applyFilters() {
    setPage(0);
    setApplied({ action, actorId, eventId });
  }
  function resetFilters() {
    setAction('');
    setActorId('');
    setEventId('');
    setPage(0);
    setApplied({ action: '', actorId: '', eventId: '' });
  }

  return (
    <div className="kx-page kx-adm">
      <header className="kx-adm__head">
        <div>
          <h1 className="kx-adm__title">{t('audit.title')}</h1>
          <p className="kx-adm__subtitle">
            {t('audit.subtitle')}
          </p>
        </div>
        <Button
          variant="secondary"
          leadingIcon={<IconDownload size={16} />}
          onClick={() => exportCsv(t, rows)}
          disabled={rows.length === 0}
        >
          {t('audit.exportCsv')}
        </Button>
      </header>

      {/* 필터 바 */}
      <section className="kx-card kx-adm-filter" aria-label={t('audit.filterAria')}>
        <div className="kx-adm-filter__grid">
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('audit.actionType')}</span>
            <input
              className="kx-adm-field__input"
              list="audit-actions"
              placeholder={t('audit.allActions')}
              value={action}
              onChange={(e) => setAction(e.target.value)}
            />
            <datalist id="audit-actions">
              {KNOWN_AUDIT_ACTIONS.map((a) => (
                <option key={a} value={a} />
              ))}
            </datalist>
          </label>
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('audit.actorId')}</span>
            <input
              className="kx-adm-field__input"
              placeholder={t('audit.actorIdPh')}
              value={actorId}
              onChange={(e) => setActorId(e.target.value)}
            />
          </label>
          <label className="kx-adm-field">
            <span className="kx-adm-field__label">{t('audit.eventId')}</span>
            <input
              className="kx-adm-field__input"
              placeholder={t('audit.eventIdPh')}
              value={eventId}
              onChange={(e) => setEventId(e.target.value)}
            />
          </label>
          <div className="kx-adm-filter__actions">
            <Button variant="ghost" onClick={resetFilters}>
              {t('audit.reset')}
            </Button>
            <Button leadingIcon={<IconSearch size={16} />} onClick={applyFilters}>
              {t('audit.applyFilter')}
            </Button>
          </div>
        </div>
      </section>

      {/* 본문 */}
      {q.isLoading && <TableSkeleton />}

      {q.isError && !q.isLoading && (
        <ErrorState message={t('audit.loadError')} onRetry={() => q.refetch()} />
      )}

      {!q.isLoading && !q.isError && (
        <section className="kx-card kx-adm-table-card" aria-label={t('audit.tableAria')}>
          {rows.length === 0 ? (
            <EmptyState
              title={t('audit.emptyTitle')}
              description={t('audit.emptyDesc')}
            />
          ) : (
            <>
              <div className="kx-table-scroll">
                <table className="kx-table kx-table--zebra kx-adm-audit">
                  <thead>
                    <tr>
                      <th>{t('audit.colTime')}</th>
                      <th>{t('audit.colUser')}</th>
                      <th>{t('audit.colAction')}</th>
                      <th>{t('audit.colTarget')}</th>
                      <th>{t('audit.colEvent')}</th>
                      <th>{t('audit.colResult')}</th>
                    </tr>
                  </thead>
                  <tbody>
                    {rows.map((r) => (
                      <tr key={r.id}>
                        <td className="kx-adm-mono">{fmtTs(r.createdAt)}</td>
                        <td>
                          <div className="kx-adm-actor">
                            <span className="kx-adm-actor__avatar" aria-hidden="true">
                              {initial(r.actorName ?? r.actorId)}
                            </span>
                            <span className="kx-adm-actor__body">
                              <span className="kx-adm-actor__name">{r.actorName ?? '—'}</span>
                              {r.actorId && (
                                <span className="kx-adm-actor__id">{r.actorId}</span>
                              )}
                            </span>
                          </div>
                        </td>
                        <td>
                          <span className="kx-adm-action">{r.action ?? '—'}</span>
                          {r.summary && <span className="kx-adm-summary">{r.summary}</span>}
                        </td>
                        <td>
                          {r.targetType ? (
                            <span className="kx-adm-target">
                              <span className="kx-adm-target__type">{r.targetType}</span>
                              {r.targetId && (
                                <span className="kx-adm-target__id">#{r.targetId}</span>
                              )}
                            </span>
                          ) : (
                            <span className="kx-adm-muted">—</span>
                          )}
                        </td>
                        <td className="kx-adm-muted">{r.eventId ?? '—'}</td>
                        <td>
                          <ResultPill value={r.result} />
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>

              <div className="kx-adm-pager">
                <p className="kx-adm-pager__info">
                  <Trans i18nKey="audit.showing" values={{ from, to, total: total.toLocaleString() }} components={[<strong className="tnum" key="a" />, <strong className="tnum" key="b" />]} />
                </p>
                <div className="kx-adm-pager__nav">
                  <Button
                    variant="ghost"
                    onClick={() => setPage((p) => Math.max(0, p - 1))}
                    disabled={page === 0}
                  >
                    {t('audit.prev')}
                  </Button>
                  <span className="kx-adm-pager__page tnum">
                    {page + 1} / {totalPages}
                  </span>
                  <Button
                    variant="ghost"
                    onClick={() => setPage((p) => Math.min(totalPages - 1, p + 1))}
                    disabled={page >= totalPages - 1}
                  >
                    {t('audit.next')}
                  </Button>
                </div>
                <label className="kx-adm-pager__size">
                  <span>{t('audit.rowsShow')}</span>
                  <select
                    className="kx-select"
                    value={size}
                    onChange={(e) => {
                      setSize(Number(e.target.value));
                      setPage(0);
                    }}
                    aria-label={t('audit.rowsPerPage')}
                  >
                    {PAGE_SIZES.map((s) => (
                      <option key={s} value={s}>
                        {t('audit.rowsN', { n: s })}
                      </option>
                    ))}
                  </select>
                </label>
              </div>
            </>
          )}
        </section>
      )}
    </div>
  );
}

function ResultPill({ value }: { value: string | null }) {
  const { t } = useTranslation();
  const v = (value ?? '').toUpperCase();
  const tone =
    v === 'SUCCESS' || v === 'OK'
      ? 'success'
      : v === 'FAILURE' || v === 'FAIL' || v === 'ERROR' || v === 'DENIED'
        ? 'error'
        : 'neutral';
  const label = tone === 'success' ? t('audit.success') : tone === 'error' ? t('audit.failure') : value ?? '—';
  return <span className={`kx-adm-pill kx-adm-pill--${tone}`}>{label}</span>;
}

function TableSkeleton() {
  return (
    <div className="kx-card" aria-hidden="true" style={{ display: 'grid', gap: 12 }}>
      {[0, 1, 2, 3, 4, 5].map((i) => (
        <Skeleton key={i} height={44} radius={6} />
      ))}
    </div>
  );
}

function initial(name: string | null | undefined): string {
  const s = (name ?? '').trim();
  return s ? s.charAt(0) : '?';
}

function fmtTs(s: string | null | undefined): string {
  if (!s) return '—';
  const d = new Date(s);
  if (Number.isNaN(d.getTime())) return s;
  const p = (n: number) => String(n).padStart(2, '0');
  return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
}

/** 현재 로드된 페이지 rows 를 CSV 로 내보낸다. IP/자격증명 컬럼은 애초에 존재하지 않는다. */
function exportCsv(t: TFunction, rows: AuditLogRow[]): void {
  if (rows.length === 0) return;
  const headers = [
    t('audit.csvTime'), t('audit.csvActorId'), t('audit.csvActorName'), t('audit.csvAction'),
    t('audit.csvTargetType'), t('audit.csvTargetId'), t('audit.csvEventId'), t('audit.csvResult'), t('audit.csvSummary'),
  ];
  const esc = (v: unknown) => {
    const s = v == null ? '' : String(v);
    return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
  };
  const lines = [
    headers.join(','),
    ...rows.map((r) =>
      [r.createdAt, r.actorId, r.actorName, r.action, r.targetType, r.targetId, r.eventId, r.result, r.summary]
        .map(esc)
        .join(','),
    ),
  ];
  const blob = new Blob(['﻿' + lines.join('\r\n')], { type: 'text/csv;charset=utf-8;' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `audit-log-${new Date().toISOString().slice(0, 10)}.csv`;
  a.click();
  URL.revokeObjectURL(url);
}
