/*
 * SCR /halls — M1 홀 배정 보드 + 자동 견적.
 * 진입: 사이드바 "홀 배정"(App.tsx 배선은 통합자). 홀매니저=배정/해제, 로그인=견적·조회.
 * 구성: ①상단 기간 필터 ②홀×기간 배정 보드(충돌 표시·해제) ③배정 모달(행사·홀·기간)
 *       ④자동 견적 패널(홀·기간·부스 규모 입력 → 요율 룰셋 라인 표시).
 * ★ 실 API 배선: GET /api/halls · /assignments · POST /assignments(409 충돌) · DELETE · POST /quote.
 *   충돌 상세는 공용 client가 409 본문을 소거하므로 GET /conflicts(사전검사)로 재조회해 표시한다.
 */
import { useMemo, useState } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import { Button } from '../../components/ui/Button';
import { EmptyState, ErrorState, Skeleton } from '../../components/ui/States';
import { Offcanvas } from '../../components/ui/Offcanvas';
import { IconGrid, IconSettlement, IconWarning } from '../../components/ui/icons';
import { ApiRequestError } from '../../api/client';
import {
  hallAssignApi,
  type AssignmentBody,
  type Conflict,
  type Hall,
  type HallAssignment,
  type QuoteResult,
} from './hallAssignApi';
import './hallassign.css';

/** 두 폐구간 [aS,aE]·[bS,bE] 겹침 여부(YYYY-MM-DD 문자열 비교 가능). */
function overlaps(aS: string | null, aE: string | null, bS: string | null, bE: string | null): boolean {
  if (!aS || !aE || !bS || !bE) return false;
  return aS <= bE && bS <= aE;
}

/** 같은 홀에서 서로 겹치는 배정 id 집합(보드 충돌 하이라이트). */
function conflictingIds(list: HallAssignment[]): Set<string> {
  const out = new Set<string>();
  for (let i = 0; i < list.length; i += 1) {
    for (let j = i + 1; j < list.length; j += 1) {
      const a = list[i];
      const b = list[j];
      if (a.hallId === b.hallId && overlaps(a.occupyStart, a.occupyEnd, b.occupyStart, b.occupyEnd)) {
        out.add(a.id);
        out.add(b.id);
      }
    }
  }
  return out;
}

function fmtKrw(n: number): string {
  return `${n.toLocaleString('ko-KR')}원`;
}

const EMPTY_FORM: AssignmentBody = { eventId: '', hallId: '', primary: true, occupyStart: '', occupyEnd: '', note: '' };

export function HallAssignmentPage() {
  const { t } = useTranslation();
  const queryClient = useQueryClient();
  const [from, setFrom] = useState('');
  const [to, setTo] = useState('');
  const [modalOpen, setModalOpen] = useState(false);
  const [form, setForm] = useState<AssignmentBody>(EMPTY_FORM);
  const [assignError, setAssignError] = useState<string | null>(null);
  const [conflictHits, setConflictHits] = useState<Conflict[]>([]);
  const [toast, setToast] = useState<string | null>(null);
  // 배정 상세 offcanvas — 칩 본문 클릭 시 우측 슬라이드
  const [detail, setDetail] = useState<HallAssignment | null>(null);
  const [detailOpen, setDetailOpen] = useState(false);

  const hallsQ = useQuery({ queryKey: ['halls'], queryFn: () => hallAssignApi.halls(), retry: false });
  const assignQ = useQuery({
    queryKey: ['hall-assignments', from, to],
    queryFn: () => hallAssignApi.assignments(from || undefined, to || undefined),
    retry: false,
  });
  const eventsQ = useQuery({ queryKey: ['hall-events'], queryFn: () => hallAssignApi.events(), retry: false, enabled: modalOpen });

  const halls = hallsQ.data ?? [];
  const assignments = assignQ.data ?? [];
  const conflictSet = useMemo(() => conflictingIds(assignments), [assignments]);
  const byHall = useMemo(() => {
    const map = new Map<string, HallAssignment[]>();
    for (const a of assignments) {
      const arr = map.get(a.hallId) ?? [];
      arr.push(a);
      map.set(a.hallId, arr);
    }
    return map;
  }, [assignments]);

  // 관리자(홀매니저) 전용 API 접근이 막히면(403) 조회 자체가 실패 — 보드는 안내로 대체.
  const boardForbidden = assignQ.error instanceof ApiRequestError && assignQ.error.code === 'FORBIDDEN';

  const assignMut = useMutation({
    mutationFn: (body: AssignmentBody) => hallAssignApi.assign(body),
    onSuccess: () => {
      setModalOpen(false);
      setForm(EMPTY_FORM);
      setAssignError(null);
      setConflictHits([]);
      setToast(t('hallassign.assignedToast'));
      queryClient.invalidateQueries({ queryKey: ['hall-assignments'] });
    },
    onError: async (err) => {
      if (err instanceof ApiRequestError && err.code === 'CONFLICT') {
        setAssignError(t('hallassign.conflictErr'));
        // 공용 client가 409 본문을 소거하므로 충돌 상세를 사전검사로 재조회.
        try {
          const hits = await hallAssignApi.conflicts(
            form.hallId,
            form.occupyStart || '',
            form.occupyEnd || '',
            form.eventId,
          );
          setConflictHits(hits);
        } catch {
          setConflictHits([]);
        }
      } else {
        setAssignError(err instanceof ApiRequestError ? err.message : t('hallassign.assignFail'));
      }
    },
  });

  const releaseMut = useMutation({
    mutationFn: (id: string) => hallAssignApi.release(id),
    onSuccess: () => {
      setToast(t('hallassign.releasedToast'));
      setDetailOpen(false);
      queryClient.invalidateQueries({ queryKey: ['hall-assignments'] });
    },
    onError: () => setToast(t('hallassign.releaseFail')),
  });

  function openModal() {
    setForm(EMPTY_FORM);
    setAssignError(null);
    setConflictHits([]);
    setModalOpen(true);
  }

  /** 상세 → 수정: 배정 값을 배정 모달에 프리필(생성 API 재사용). */
  function openModalWith(a: HallAssignment) {
    setForm({
      eventId: a.eventId,
      hallId: a.hallId,
      primary: a.primary,
      occupyStart: a.occupyStart ?? '',
      occupyEnd: a.occupyEnd ?? '',
      note: a.note ?? '',
    });
    setAssignError(null);
    setConflictHits([]);
    setDetailOpen(false);
    setModalOpen(true);
  }

  function openDetail(a: HallAssignment) {
    setDetail(a);
    setDetailOpen(true);
  }

  function onPickEvent(eventId: string) {
    const ev = eventsQ.data?.find((e) => e.id === eventId);
    setForm((f) => ({
      ...f,
      eventId,
      occupyStart: ev?.startDate ?? f.occupyStart,
      occupyEnd: ev?.endDate ?? f.occupyEnd,
    }));
  }

  function submitAssign() {
    if (!form.eventId || !form.hallId) {
      setAssignError(t('hallassign.pickEventHall'));
      return;
    }
    setAssignError(null);
    setConflictHits([]);
    assignMut.mutate(form);
  }

  return (
    <div className="kx-page kx-hall">
      {toast && <div className="kx-hall__toast" role="status" onClick={() => setToast(null)}>{toast}</div>}

      <header className="kx-hall__top">
        <div>
          <h1>{t('hallassign.title')}</h1>
          <p className="kx-card__hint">{t('hallassign.subtitle')}</p>
        </div>
        <div className="kx-hall__filter">
          <label>
            {t('hallassign.start')}
            <input className="kx-select" type="date" value={from} onChange={(e) => setFrom(e.target.value)} />
          </label>
          <label>
            {t('hallassign.end')}
            <input className="kx-select" type="date" value={to} onChange={(e) => setTo(e.target.value)} />
          </label>
          <Button variant="primary" onClick={openModal}>{t('hallassign.newAssign')}</Button>
        </div>
      </header>

      {/* ── 배정 보드 ── */}
      <section className="kx-card">
        <div className="kx-card__head">
          <h2><IconGrid className="kx-title-ic" size={18} />{t('hallassign.board')}</h2>
          <span className="kx-card__hint">{t('hallassign.boardHint')}</span>
        </div>
        {assignQ.isLoading || hallsQ.isLoading ? (
          <div className="kx-hall__rows"><Skeleton height={40} /><Skeleton height={40} /><Skeleton height={40} /></div>
        ) : boardForbidden ? (
          <EmptyState title={t('hallassign.forbiddenTitle')} description={t('hallassign.forbiddenDesc')} />
        ) : assignQ.error ? (
          <ErrorState onRetry={() => assignQ.refetch()} />
        ) : halls.length === 0 ? (
          <EmptyState title={t('hallassign.noHalls')} />
        ) : (
          <div className="kx-hall__board">
            {halls.map((h: Hall) => {
              const rows = byHall.get(h.id) ?? [];
              return (
                <div className="kx-hall__row" key={h.id}>
                  <div className="kx-hall__rowhead">
                    <span className="kx-hall__hallname">{h.label}</span>
                    <span className="kx-hall__area">{h.areaM2?.toLocaleString('ko-KR')}㎡</span>
                  </div>
                  <div className="kx-hall__chips">
                    {rows.length === 0 ? (
                      <span className="kx-hall__idle">{t('hallassign.noAssign')}</span>
                    ) : (
                      rows.map((a) => {
                        const conflict = conflictSet.has(a.id);
                        return (
                          <span
                            key={a.id}
                            className={`kx-hall__chip${conflict ? ' is-conflict' : ''}${a.primary ? ' is-primary' : ''}`}
                            title={`${a.occupyStart ?? '?'} ~ ${a.occupyEnd ?? '?'}`}
                          >
                            <span
                              className="kx-hall__chipbody"
                              role="button"
                              tabIndex={0}
                              aria-label={t('hallassign.openDetail', { event: a.eventName })}
                              onClick={() => openDetail(a)}
                              onKeyDown={(e) => {
                                if (e.key === 'Enter' || e.key === ' ') {
                                  e.preventDefault();
                                  openDetail(a);
                                }
                              }}
                            >
                              {conflict && <IconWarning size={13} />}
                              <span className="kx-hall__chiptext">
                                {a.eventName}
                                <em>{a.occupyStart} ~ {a.occupyEnd}</em>
                              </span>
                            </span>
                            <button
                              type="button"
                              className="kx-hall__chipx"
                              aria-label={t('hallassign.release')}
                              onClick={() => {
                                if (window.confirm(t('hallassign.releaseConfirm', { event: a.eventName, hall: a.hallLabel }))) {
                                  releaseMut.mutate(a.id);
                                }
                              }}
                            >×</button>
                          </span>
                        );
                      })
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        )}
      </section>

      {/* ── 자동 견적 패널 ── */}
      <QuotePanel halls={halls} />

      {/* ── 배정 모달 ── */}
      {modalOpen && (
        <div className="kx-hall__backdrop" onClick={() => setModalOpen(false)}>
          <div className="kx-hall__modal" role="dialog" aria-modal="true" onClick={(e) => e.stopPropagation()}>
            <div className="kx-card__head">
              <h2>{t('hallassign.modalTitle')}</h2>
              <button type="button" className="kx-hall__chipx" aria-label={t('hallassign.close')} onClick={() => setModalOpen(false)}>×</button>
            </div>
            <div className="kx-hall__form">
              <label>
                {t('hallassign.event')}
                <select className="kx-select" value={form.eventId} onChange={(e) => onPickEvent(e.target.value)}>
                  <option value="">{t('hallassign.pickEvent')}</option>
                  {(eventsQ.data ?? []).map((e) => (
                    <option key={e.id} value={e.id}>{e.name}</option>
                  ))}
                </select>
              </label>
              <label>
                {t('hallassign.hall')}
                <select className="kx-select" value={form.hallId} onChange={(e) => setForm((f) => ({ ...f, hallId: e.target.value }))}>
                  <option value="">{t('hallassign.pickHall')}</option>
                  {halls.map((h) => (
                    <option key={h.id} value={h.id}>{h.label}</option>
                  ))}
                </select>
              </label>
              <div className="kx-hall__form2">
                <label>
                  {t('hallassign.occupyStart')}
                  <input className="kx-select" type="date" value={form.occupyStart ?? ''} onChange={(e) => setForm((f) => ({ ...f, occupyStart: e.target.value }))} />
                </label>
                <label>
                  {t('hallassign.occupyEnd')}
                  <input className="kx-select" type="date" value={form.occupyEnd ?? ''} onChange={(e) => setForm((f) => ({ ...f, occupyEnd: e.target.value }))} />
                </label>
              </div>
              <label className="kx-hall__check">
                <input type="checkbox" checked={form.primary} onChange={(e) => setForm((f) => ({ ...f, primary: e.target.checked }))} />
                {t('hallassign.primary')}
              </label>
              <label>
                {t('hallassign.note')}
                <input className="kx-select" type="text" value={form.note ?? ''} onChange={(e) => setForm((f) => ({ ...f, note: e.target.value }))} placeholder={t('hallassign.optional')} />
              </label>

              {assignError && (
                <div className="kx-hall__err" role="alert">
                  <IconWarning size={15} /> {assignError}
                  {conflictHits.length > 0 && (
                    <ul className="kx-hall__conflicts">
                      {conflictHits.map((c) => (
                        <li key={c.assignmentId}>{c.eventName} · {c.hallLabel} ({c.occupyStart} ~ {c.occupyEnd})</li>
                      ))}
                    </ul>
                  )}
                </div>
              )}
            </div>
            <div className="kx-hall__modalfoot">
              <Button variant="ghost" onClick={() => setModalOpen(false)}>{t('hallassign.cancel')}</Button>
              <Button variant="primary" onClick={submitAssign} disabled={assignMut.isPending}>
                {assignMut.isPending ? t('hallassign.assigning') : t('hallassign.assign')}
              </Button>
            </div>
          </div>
        </div>
      )}

      {/* ── 배정 상세 offcanvas(우측 슬라이드) ── */}
      <Offcanvas
        open={detailOpen}
        onClose={() => setDetailOpen(false)}
        title={detail ? detail.eventName : t('hallassign.detailTitle')}
        footer={
          detail ? (
            <>
              <Button variant="ghost" onClick={() => detail && openModalWith(detail)}>
                {t('hallassign.edit')}
              </Button>
              <Button
                variant="danger"
                disabled={releaseMut.isPending}
                onClick={() => {
                  if (detail && window.confirm(t('hallassign.releaseConfirm', { event: detail.eventName, hall: detail.hallLabel }))) {
                    releaseMut.mutate(detail.id);
                  }
                }}
              >
                {t('hallassign.release')}
              </Button>
            </>
          ) : undefined
        }
      >
        {detail && <AssignmentDetail assignment={detail} allAssignments={assignments} />}
      </Offcanvas>
    </div>
  );
}

/** 배정 상세 본문 — 기간·홀·상태·충돌 행사·자동 견적 요약. */
function AssignmentDetail({ assignment, allAssignments }: { assignment: HallAssignment; allAssignments: HallAssignment[] }) {
  const { t } = useTranslation();
  const a = assignment;

  // 같은 홀에서 이 배정과 겹치는 다른 배정(충돌).
  const conflicts = useMemo(
    () =>
      allAssignments.filter(
        (o) => o.id !== a.id && o.hallId === a.hallId && overlaps(a.occupyStart, a.occupyEnd, o.occupyStart, o.occupyEnd),
      ),
    [allAssignments, a],
  );

  // 자동 견적 요약(홀+기간) — 룰셋 재사용. 기간이 있을 때만.
  const quoteQ = useQuery({
    queryKey: ['hall-assign-detail-quote', a.hallId, a.occupyStart, a.occupyEnd],
    queryFn: () => hallAssignApi.quote({ hallIds: [a.hallId], startDate: a.occupyStart!, endDate: a.occupyEnd! }),
    enabled: detailQuoteReady(a),
    retry: false,
    staleTime: 60_000,
  });

  return (
    <div className="kx-hall__detail">
      <dl className="kx-hall__detailgrid">
        <div>
          <dt>{t('hallassign.dHall')}</dt>
          <dd>{a.hallLabel}</dd>
        </div>
        <div>
          <dt>{t('hallassign.dPeriod')}</dt>
          <dd>{a.occupyStart ?? '?'} ~ {a.occupyEnd ?? '?'}</dd>
        </div>
        <div>
          <dt>{t('hallassign.dStatus')}</dt>
          <dd>
            <span className={`kx-hall__statusbadge${a.primary ? ' is-primary' : ''}`}>{a.status || '-'}</span>
            {a.primary && <span className="kx-hall__primarytag">{t('hallassign.primaryTag')}</span>}
          </dd>
        </div>
        {a.note && (
          <div>
            <dt>{t('hallassign.dNote')}</dt>
            <dd>{a.note}</dd>
          </div>
        )}
      </dl>

      {/* 충돌 여부 */}
      <section className="kx-hall__detailsec">
        <h3>{t('hallassign.dConflict')}</h3>
        {conflicts.length === 0 ? (
          <p className="kx-hall__ok">{t('hallassign.dNoConflict')}</p>
        ) : (
          <ul className="kx-hall__conflicts kx-hall__detailconflicts">
            {conflicts.map((c) => (
              <li key={c.id}>
                <IconWarning size={14} /> {c.eventName} · {c.hallLabel} ({c.occupyStart} ~ {c.occupyEnd})
              </li>
            ))}
          </ul>
        )}
      </section>

      {/* 자동 견적 요약 */}
      <section className="kx-hall__detailsec">
        <h3>{t('hallassign.dQuote')}</h3>
        {!detailQuoteReady(a) ? (
          <p className="kx-card__hint">{t('hallassign.dQuoteNoPeriod')}</p>
        ) : quoteQ.isLoading ? (
          <Skeleton height={72} />
        ) : quoteQ.error || !quoteQ.data ? (
          <p className="kx-card__hint">{t('hallassign.dQuoteFail')}</p>
        ) : (
          <div className="kx-hall__detailquote">
            <div className="kx-hall__detailquoterow">
              <span>{t('hallassign.rentalTotal', { days: quoteQ.data.days })}</span>
              <strong className="kx-hall__num">{fmtKrw(quoteQ.data.total)}</strong>
            </div>
            <div className="kx-hall__detailquoterow">
              <span>{t('hallassign.deposit')}</span>
              <span className="kx-hall__num">{fmtKrw(quoteQ.data.depositMin)} ~ {fmtKrw(quoteQ.data.depositMax)}</span>
            </div>
            {quoteQ.data.disclaimer && (
              <p className="kx-card__hint">{quoteQ.data.disclaimer} {t('hallassign.ruleset', { v: quoteQ.data.rulesetVersion })}</p>
            )}
          </div>
        )}
      </section>
    </div>
  );
}

/** 상세 견적 조회 가능 여부(홀·기간 확보). */
function detailQuoteReady(a: HallAssignment): boolean {
  return Boolean(a.hallId && a.occupyStart && a.occupyEnd);
}

/** 자동 견적 패널 — 홀 다중 선택 + 기간 + 부스 규모 → 요율 룰셋 라인. */
function QuotePanel({ halls }: { halls: Hall[] }) {
  const { t } = useTranslation();
  const [picked, setPicked] = useState<string[]>([]);
  const [start, setStart] = useState('');
  const [end, setEnd] = useState('');
  const [boothCount, setBoothCount] = useState('');
  const [result, setResult] = useState<QuoteResult | null>(null);
  const [err, setErr] = useState<string | null>(null);

  const quoteMut = useMutation({
    mutationFn: () =>
      hallAssignApi.quote({
        hallIds: picked,
        startDate: start,
        endDate: end,
        boothCount: boothCount ? Number(boothCount) : undefined,
      }),
    onSuccess: (r) => { setResult(r); setErr(null); },
    onError: (e) => { setErr(e instanceof ApiRequestError ? e.message : t('hallassign.quoteFail')); setResult(null); },
  });

  function toggleHall(id: string) {
    setPicked((p) => (p.includes(id) ? p.filter((x) => x !== id) : [...p, id]));
  }

  function run() {
    if (picked.length === 0 || !start || !end) {
      setErr(t('hallassign.quoteReq'));
      return;
    }
    setErr(null);
    quoteMut.mutate();
  }

  return (
    <section className="kx-card">
      <div className="kx-card__head">
        <h2><IconSettlement className="kx-title-ic" size={18} />{t('hallassign.autoQuote')}</h2>
        <span className="kx-card__hint">{t('hallassign.quoteHint')}</span>
      </div>
      <div className="kx-hall__quoteform">
        <div className="kx-hall__hallpick">
          {halls.map((h) => (
            <label key={h.id} className={`kx-hall__pill${picked.includes(h.id) ? ' is-on' : ''}`}>
              <input type="checkbox" checked={picked.includes(h.id)} onChange={() => toggleHall(h.id)} />
              {h.label}
            </label>
          ))}
        </div>
        <div className="kx-hall__quoteinputs">
          <label>{t('hallassign.startDate')}<input className="kx-select" type="date" value={start} onChange={(e) => setStart(e.target.value)} /></label>
          <label>{t('hallassign.endDate')}<input className="kx-select" type="date" value={end} onChange={(e) => setEnd(e.target.value)} /></label>
          <label>{t('hallassign.boothSize')}<input className="kx-select" type="number" min={0} value={boothCount} onChange={(e) => setBoothCount(e.target.value)} placeholder={t('hallassign.countPh')} /></label>
          <Button variant="ai" onClick={run} disabled={quoteMut.isPending}>{quoteMut.isPending ? t('hallassign.calculating') : t('hallassign.calcQuote')}</Button>
        </div>
      </div>

      {err && <div className="kx-hall__err" role="alert"><IconWarning size={15} /> {err}</div>}

      {result && (
        <div className="kx-hall__quoteresult">
          <table className="kx-table">
            <thead>
              <tr><th>{t('hallassign.qItem')}</th><th>{t('hallassign.qBasis')}</th><th className="kx-hall__num">{t('hallassign.qAmount')}</th></tr>
            </thead>
            <tbody>
              {result.lines.map((l, i) => (
                <tr key={`${l.code}-${i}`} className={l.amount < 0 ? 'kx-hall__discount' : ''}>
                  <td>{l.label}</td>
                  <td className="kx-hall__basis">{l.basis}</td>
                  <td className="kx-hall__num">{fmtKrw(l.amount)}</td>
                </tr>
              ))}
            </tbody>
            <tfoot>
              <tr><td colSpan={2}>{t('hallassign.rentalSubtotal')}</td><td className="kx-hall__num">{fmtKrw(result.rentalSubtotal)}</td></tr>
              <tr className="kx-hall__total"><td colSpan={2}>{t('hallassign.rentalTotal', { days: result.days })}</td><td className="kx-hall__num">{fmtKrw(result.total)}</td></tr>
              <tr><td colSpan={2}>{t('hallassign.deposit')}</td><td className="kx-hall__num">{fmtKrw(result.depositMin)} ~ {fmtKrw(result.depositMax)}</td></tr>
            </tfoot>
          </table>
          {result.capacityNote && <p className="kx-hall__note"><IconWarning size={14} /> {result.capacityNote}</p>}
          {result.disclaimer && <p className="kx-card__hint">{result.disclaimer} {t('hallassign.ruleset', { v: result.rulesetVersion })}</p>}
        </div>
      )}
    </section>
  );
}
