import { useMemo, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import {
  Bar,
  BarChart,
  CartesianGrid,
  ResponsiveContainer,
  Tooltip,
  XAxis,
  YAxis,
} from 'recharts';
import { Button } from '../../components/ui/Button';
import { EmptyState, ErrorState, Skeleton } from '../../components/ui/States';
import { IconSearch, IconWifiOff, IconCheckCircle, IconClock, IconGrid, IconUsers } from '../../components/ui/icons';
import { ApiRequestError } from '../../api/client';
import { useResolvedEventId } from '../../hooks/useResolvedEventId';
import { CHART } from '../chartColors';
import { REG_TYPE_LABEL, type RegVisitorType } from './sampleVisitor';
import {
  visitorApi,
  type CheckinResultDto,
  type CheckinSearchItemDto,
  type CheckinStatsDto,
} from './visitorApi';
import './visitor.css';
import './checkin.css';

/*
 * SCR-31 현장 체크인 데스크 / 키오스크 (M10). Stitch scr_31_checkin_desk 이식.
 * 정상 경로: POST /api/events/{eventId}/checkin (토큰/등록번호), GET /checkin/search, GET /checkin/stats,
 *   POST /visitors/{id}/badge/reissue. 3상태(로딩/빈/에러) 준수.
 * ★ 보안 불변: 관람객 이름·연락처는 서버 마스킹 필드만 소비(원문 미노출, N2/R10).
 * ★ 카메라 대신 토큰 입력 + 수동 검색으로 실동작(요청 사양). 오프라인 폴백 배지 표기(F049).
 */
export function CheckinDeskPage() {
  const eventId = useResolvedEventId();
  const qc = useQueryClient();
  const [kiosk, setKiosk] = useState(false);
  const [token, setToken] = useState('');
  const [search, setSearch] = useState('');
  const [searchResults, setSearchResults] = useState<CheckinSearchItemDto[] | null>(null);
  const [searchError, setSearchError] = useState<string | null>(null);
  const [card, setCard] = useState<CheckinResultDto | null>(null);
  const [scanError, setScanError] = useState<string | null>(null);

  const statsQ = useQuery({
    queryKey: ['checkin-stats', eventId],
    queryFn: () => visitorApi.checkinStats(eventId as string),
    enabled: !!eventId,
    retry: false,
    refetchInterval: 15000,
  });

  const degraded = isDegradable(statsQ.error);
  const stats: CheckinStatsDto | null = statsQ.data ?? (degraded ? SAMPLE_STATS : null);
  const hardError = statsQ.isError && !degraded;

  const checkinMut = useMutation({
    mutationFn: (body: { token?: string; registrationId?: string }) =>
      visitorApi.checkin(eventId as string, body),
    onSuccess: (res) => {
      setCard(res);
      setScanError(null);
      setToken('');
      setSearchResults(null);
      setSearch('');
      qc.invalidateQueries({ queryKey: ['checkin-stats', eventId] });
    },
    onError: (e) => {
      setCard(null);
      setScanError(
        e instanceof ApiRequestError && e.code === 'NOT_FOUND'
          ? '등록 정보를 찾을 수 없습니다 — 현장 등록이 필요합니다.'
          : '체크인 처리 중 오류가 발생했습니다. 다시 시도해 주세요.',
      );
    },
  });

  const reissueMut = useMutation({
    mutationFn: (registrationId: string) => visitorApi.reissueBadge(eventId as string, registrationId),
    onSuccess: (res) =>
      setCard((c) => (c ? { ...c, badgeCode: res.badgeCode, badgeIssued: true } : c)),
  });

  const runSearch = async () => {
    if (!eventId || search.trim().length < 2) {
      setSearchError('검색어는 2자 이상 입력해 주세요.');
      return;
    }
    setSearchError(null);
    try {
      const rows = await visitorApi.checkinSearch(eventId, search.trim());
      setSearchResults(rows);
    } catch (e) {
      setSearchResults([]);
      setSearchError(
        e instanceof ApiRequestError && e.code === 'NETWORK'
          ? '네트워크 연결을 확인해 주세요.'
          : '검색 중 오류가 발생했습니다.',
      );
    }
  };

  const submitToken = () => {
    if (!token.trim()) {
      setScanError('QR 토큰(배지 코드)을 입력해 주세요.');
      return;
    }
    checkinMut.mutate({ token: token.trim() });
  };

  const chartData = useMemo(
    () => (stats?.byHour ?? []).map((b) => ({ hour: b.hour, count: b.count })),
    [stats],
  );

  if (!eventId) {
    return (
      <div className="kx-vis">
        <EmptyState title="행사를 선택해 주세요" description="체크인을 진행할 행사가 지정되지 않았습니다." />
      </div>
    );
  }

  return (
    <div className={`kx-vis kx-checkin ${kiosk ? 'is-kiosk' : ''}`}>
      <header className="kx-vis__head">
        <div>
          <h1 className="kx-vis__title">현장 체크인 데스크</h1>
          <p className="kx-vis__subtitle">배지 QR 스캔 · 수동 검색 · 실시간 입장 집계</p>
        </div>
        <div className="kx-vis__head-actions">
          {degraded && (
            <span className="kx-vis__degraded" title="집계 API 미연결 — 시연 데이터">
              <IconWifiOff size={14} /> 오프라인 — 로컬 저장 후 동기화
            </span>
          )}
          <button
            type="button"
            className={`kx-checkin__kiosk-toggle ${kiosk ? 'is-on' : ''}`}
            aria-pressed={kiosk}
            onClick={() => setKiosk((v) => !v)}
          >
            <IconGrid size={16} /> 키오스크 모드
          </button>
        </div>
      </header>

      <div className="kx-checkin__grid">
        {/* 좌: 스캔 존 + 수동 검색 */}
        <section className="kx-card kx-checkin__scan" aria-label="배지 스캔">
          <div className="kx-checkin__frame" aria-hidden="true">
            <span className="kx-checkin__frame-corner tl" />
            <span className="kx-checkin__frame-corner tr" />
            <span className="kx-checkin__frame-corner bl" />
            <span className="kx-checkin__frame-corner br" />
            <ScanGlyph />
            <p className="kx-checkin__frame-hint">배지 QR을 스캔하세요</p>
          </div>

          <form
            className="kx-checkin__token"
            onSubmit={(e) => {
              e.preventDefault();
              submitToken();
            }}
          >
            <label htmlFor="kx-token" className="kx-checkin__label">QR 토큰 / 배지 코드 입력</label>
            <div className="kx-checkin__token-row">
              <input
                id="kx-token"
                className="kx-checkin__input"
                value={token}
                onChange={(e) => setToken(e.target.value)}
                placeholder="예: QR-XXXX 또는 KTX-V-0001"
                autoComplete="off"
              />
              <Button type="submit" disabled={checkinMut.isPending}>
                {checkinMut.isPending ? '확인 중…' : '체크인'}
              </Button>
            </div>
          </form>

          <div className="kx-checkin__divider"><span>또는 수동 검색</span></div>

          <div className="kx-checkin__search">
            <label htmlFor="kx-search" className="kx-checkin__label">이름 · 연락처 · 등록번호</label>
            <div className="kx-checkin__token-row">
              <input
                id="kx-search"
                className="kx-checkin__input"
                value={search}
                onChange={(e) => setSearch(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter') {
                    e.preventDefault();
                    runSearch();
                  }
                }}
                placeholder="검색어 2자 이상"
                autoComplete="off"
              />
              <Button variant="secondary" leadingIcon={<IconSearch size={16} />} onClick={runSearch}>
                검색
              </Button>
            </div>
            {searchError && <p className="kx-checkin__err" role="alert">{searchError}</p>}

            {searchResults && searchResults.length > 0 && (
              <ul className="kx-checkin__results" aria-label="검색 결과">
                {searchResults.map((r) => (
                  <li key={r.registrationId} className="kx-checkin__result">
                    <span className="kx-vis__avatar" aria-hidden="true">{r.nameMasked.charAt(0)}</span>
                    <div className="kx-checkin__result-info">
                      <span className="kx-checkin__result-name">
                        {r.nameMasked} <TypePill type={r.type} />
                      </span>
                      <span className="kx-checkin__result-meta">
                        {r.company ?? '-'} · {r.phoneMasked ?? '-'} · {r.badgeCode ?? '-'}
                      </span>
                    </div>
                    {r.checkinState === 'done' ? (
                      <span className="kx-checkin__done-tag"><IconCheckCircle size={14} /> 완료</span>
                    ) : (
                      <Button
                        variant="secondary"
                        onClick={() => checkinMut.mutate({ registrationId: r.registrationId })}
                        disabled={checkinMut.isPending}
                      >
                        체크인
                      </Button>
                    )}
                  </li>
                ))}
              </ul>
            )}
            {searchResults && searchResults.length === 0 && !searchError && (
              <p className="kx-checkin__empty">검색 결과가 없습니다 — 현장 등록을 진행해 주세요.</p>
            )}
          </div>
        </section>

        {/* 중: 스캔 결과 카드 */}
        <section className="kx-card kx-checkin__result-card" aria-label="체크인 결과">
          {scanError && (
            <div className="kx-checkin__scan-error" role="alert">
              <p>{scanError}</p>
              <Button variant="secondary" onClick={() => setScanError(null)}>닫기</Button>
            </div>
          )}

          {!card && !scanError && (
            <div className="kx-checkin__idle">
              <span className="kx-checkin__pulse" aria-hidden="true" />
              <p>배지를 스캔하거나 검색해 체크인을 시작하세요.</p>
            </div>
          )}

          {card && (
            <div className={`kx-checkin__visitor ${card.alreadyCheckedIn ? 'is-dup' : 'is-ok'}`}>
              <div className="kx-checkin__visitor-status">
                {card.alreadyCheckedIn ? (
                  <span className="kx-checkin__badge-dup">이미 체크인됨</span>
                ) : (
                  <span className="kx-checkin__badge-ok"><IconCheckCircle size={18} /> 체크인 완료</span>
                )}
              </div>
              <span className="kx-vis__avatar kx-vis__avatar--lg" aria-hidden="true">
                {card.nameMasked.charAt(0)}
              </span>
              <h2 className="kx-checkin__visitor-name">{card.nameMasked}</h2>
              <p className="kx-checkin__visitor-meta">
                <TypePill type={card.type} /> · {card.company ?? '-'}
              </p>
              <dl className="kx-checkin__visitor-dl">
                <div><dt>배지 번호</dt><dd className="tnum">{card.badgeCode ?? '-'}</dd></div>
                <div><dt>체크인 시각</dt><dd className="tnum">{card.checkinAt ?? '-'}</dd></div>
              </dl>
              <div className="kx-checkin__visitor-actions">
                <Button block leadingIcon={<QrGlyph size={16} />}>즉석 배지 인쇄</Button>
                <Button
                  variant="secondary"
                  block
                  onClick={() => reissueMut.mutate(card.registrationId)}
                  disabled={reissueMut.isPending}
                >
                  {reissueMut.isPending ? '재발급 중…' : '배지 재발급'}
                </Button>
              </div>
              <p className="kx-vis__pii-note">개인정보 보호 · 이름 마스킹 표기(원문 미표시)</p>
            </div>
          )}
        </section>

        {/* 우: 실시간 입장 집계 */}
        <aside className="kx-checkin__side" aria-label="실시간 입장">
          {statsQ.isLoading && !degraded && (
            <div style={{ display: 'grid', gap: 12 }}>
              <Skeleton height={120} radius={12} />
              <Skeleton height={220} radius={12} />
            </div>
          )}

          {hardError && (
            <ErrorState message="입장 집계를 불러오지 못했습니다." onRetry={() => statsQ.refetch()} />
          )}

          {stats && (
            <>
              <div className="kx-card kx-checkin__inside">
                <span className="kx-checkin__inside-label"><IconUsers size={16} /> 현재 장내 추정</span>
                <strong className="kx-checkin__inside-num tnum">{stats.inside.toLocaleString()}명</strong>
                <div className="kx-checkin__inside-sub">
                  <span>사전등록 <b className="tnum">{stats.preRegistered.toLocaleString()}</b></span>
                  <span>체크인 <b className="tnum">{stats.checkedIn.toLocaleString()}</b></span>
                </div>
              </div>

              <div className="kx-card kx-checkin__hours">
                <div className="kx-card__head"><h2><IconClock className="kx-title-ic" size={18} />시간대별 체크인</h2></div>
                {chartData.length === 0 ? (
                  <EmptyState title="집계 없음" description="체크인이 시작되면 시간대별 추이가 표시됩니다." />
                ) : (
                  <ResponsiveContainer width="100%" height={200}>
                    <BarChart data={chartData} margin={{ top: 8, right: 8, bottom: 0, left: -12 }}>
                      <CartesianGrid stroke={CHART.neutral200} strokeDasharray="3 3" vertical={false} />
                      <XAxis dataKey="hour" tick={{ fontSize: 11, fill: CHART.slate }} tickLine={false} axisLine={{ stroke: CHART.neutral200 }} />
                      <YAxis tick={{ fontSize: 11, fill: CHART.slate }} tickLine={false} axisLine={false} width={40} allowDecimals={false} />
                      <Tooltip contentStyle={TOOLTIP_STYLE} formatter={(v) => [`${(v as number).toLocaleString()}명`, '체크인']} />
                      <Bar dataKey="count" fill={CHART.primary600} radius={[4, 4, 0, 0]} maxBarSize={28} />
                    </BarChart>
                  </ResponsiveContainer>
                )}
              </div>
            </>
          )}
        </aside>
      </div>
    </div>
  );
}

const TOOLTIP_STYLE = {
  fontSize: 12,
  borderRadius: 8,
  border: '1px solid #E4E7EC',
  boxShadow: '0 4px 12px rgba(16,24,40,0.1)',
} as const;

const KNOWN_TYPES: RegVisitorType[] = ['visitor', 'buyer', 'vip'];
function TypePill({ type }: { type: string }) {
  const t = (KNOWN_TYPES as string[]).includes(type) ? (type as RegVisitorType) : 'visitor';
  return <span className={`kx-vis__type is-${t}`}>{REG_TYPE_LABEL[t]}</span>;
}

/** 폴백 집계(오프라인 강등 시). */
const SAMPLE_STATS: CheckinStatsDto = {
  preRegistered: 12480,
  checkedIn: 8210,
  inside: 7553,
  byHour: [
    { hour: '09시', count: 1240 },
    { hour: '10시', count: 2180 },
    { hour: '11시', count: 1760 },
    { hour: '12시', count: 980 },
    { hour: '13시', count: 1150 },
    { hour: '14시', count: 900 },
  ],
};

function isDegradable(error: unknown): boolean {
  return (
    error instanceof ApiRequestError &&
    (error.code === 'NETWORK' || error.code === 'NOT_FOUND' || error.code === 'NOT_IMPLEMENTED')
  );
}

/** 스캔 프레임 글리프(선 SVG). */
function ScanGlyph() {
  return (
    <svg width={72} height={72} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.4} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
      <path d="M4 8V6a2 2 0 0 1 2-2h2M16 4h2a2 2 0 0 1 2 2v2M20 16v2a2 2 0 0 1-2 2h-2M8 20H6a2 2 0 0 1-2-2v-2" />
      <path d="M4 12h16" className="kx-checkin__scanline" />
    </svg>
  );
}

/** QR 글리프(선 SVG, 장식). */
function QrGlyph({ size = 40 }: { size?: number }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <path d="M3 3h7v7H3V3zm2 2v3h3V5H5zm-2 9h7v7H3v-7zm2 2v3h3v-3H5zM14 3h7v7h-7V3zm2 2v3h3V5h-3zM14 14h3v3h-3v-3zm4 0h3v3h-3v-3zm-4 4h3v3h-3v-3zm4 0h3v3h-3v-3z" />
    </svg>
  );
}
