import { useEffect, useMemo, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { layoutApi, renderApi, hallTreeApi } from '../../api/endpoints';
import { ApiRequestError } from '../../api/client';
import { subscribeRenderJob } from '../../api/websocket';
import { Button } from '../../components/ui/Button';
import { AiLabel } from '../../components/ui/Badge';
import { AiImage } from '../../components/ui/AiImage';
import { ErrorState } from '../../components/ui/States';
import type { AutoLayoutOption, HallTreeDto, RenderJobDto } from '../../api/types';
import './auto-layout.css';

/*
 * AI 자동배치 3단계 위저드 (소유자 지시 2026-07-14 "사용자가 쉽게").
 *  ① 어디에 — 평면도 트리 선택: 대분류(전시장) > 중분류(홀) > 소분류(구역 1A/1B…)
 *  ② 어떻게 — 자연어 한 줄 + AI 해석 폼(최종 권위는 폼)
 *  ③ 고르기 — 3안 비교 → 조감 이미지는 버튼 클릭 시에만 생성(쿼터 보호) → 클릭 확대·저장 →
 *             "이 안으로 편집 시작" 시 apply-option으로 실제 저장.
 */
interface AutoLayoutDialogProps {
  eventId: string;
  hallId: string; // 초기 홀(라우트) — 위저드에서 변경 가능
  onClose: () => void;
  /** 적용 완료(서버 저장 후) — 적용된 홀로 이동/재조회는 상위 책임. */
  onApply: (option: AutoLayoutOption, appliedHallId: string) => void;
}

const DEFAULT_REQ = {
  targetBoothCount: 510,
  premiumRatio: 0.15,
  stageCount: 1,
  loungeCount: 1,
  mainEntranceCount: 2,
  optionCount: 3,
};

type Phase = 'place' | 'form' | 'generating' | 'result';

export function AutoLayoutDialog({ eventId, hallId, onClose, onApply }: AutoLayoutDialogProps) {
  const [phase, setPhase] = useState<Phase>('place');
  const [req, setReq] = useState(DEFAULT_REQ);
  const [options, setOptions] = useState<AutoLayoutOption[]>([]);
  const [renderJobs, setRenderJobs] = useState<Record<string, RenderJobDto>>({});
  const [previewJobIds, setPreviewJobIds] = useState<Record<string, string>>({});
  const [previewBusy, setPreviewBusy] = useState<Record<string, boolean>>({});
  const [selected, setSelected] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [applying, setApplying] = useState(false);
  const [lightbox, setLightbox] = useState<{ url: string; alt: string } | null>(null);

  // ① 평면도 트리 선택 상태
  const treeQuery = useQuery<HallTreeDto>({ queryKey: ['halls-tree'], queryFn: hallTreeApi.get, staleTime: 600_000 });
  const [selHall, setSelHall] = useState(hallId);
  const [selZone, setSelZone] = useState<string>(''); // '' = 홀 전체
  const centers = treeQuery.data?.centers ?? [];
  const currentCenter = useMemo(
    () => centers.find((c) => c.halls.some((h) => h.id === selHall)) ?? centers[0] ?? null,
    [centers, selHall],
  );
  const [selCenter, setSelCenter] = useState<number | null>(null);
  const activeCenter = centers.find((c) => c.center === selCenter) ?? currentCenter;
  const activeHall = activeCenter?.halls.find((h) => h.id === selHall) ?? null;

  // 자연어 조건 해석 상태 (AI가 문장을 폼 값으로 파싱 — 최종 권위는 폼).
  const [nlText, setNlText] = useState('');
  const [interpreting, setInterpreting] = useState(false);
  const [nlNote, setNlNote] = useState<string | null>(null);
  const [nlDegraded, setNlDegraded] = useState(false);

  async function interpret() {
    if (!nlText.trim() || interpreting) return;
    setInterpreting(true);
    setError(null);
    try {
      const res = await layoutApi.interpret(eventId, selHall, { text: nlText });
      setReq({
        targetBoothCount: res.request.targetBoothCount,
        premiumRatio: res.request.premiumRatio,
        stageCount: res.request.stageCount,
        loungeCount: res.request.loungeCount,
        mainEntranceCount: res.request.mainEntranceCount,
        optionCount: Math.min(3, Math.max(1, res.request.optionCount)),
      });
      setNlNote(res.interpretedNote);
      setNlDegraded(res.degraded);
    } catch {
      setNlNote('AI 해석을 사용할 수 없습니다. 아래 값을 직접 입력해 주세요.');
      setNlDegraded(true);
    } finally {
      setInterpreting(false);
    }
  }

  // 조감 RenderJob 구독 — 버튼으로 발행한 잡만(자동 발행 없음, 2026-07-14).
  useEffect(() => {
    const entries = Object.entries(previewJobIds);
    if (entries.length === 0) return;
    const unsubs = entries.map(([optionId, jobId]) =>
      subscribeRenderJob(jobId, (job) => setRenderJobs((prev) => ({ ...prev, [optionId]: job }))),
    );
    entries.forEach(async ([optionId, jobId]) => {
      try {
        const job = await renderApi.status(eventId, jobId);
        setRenderJobs((prev) => ({ ...prev, [optionId]: job }));
      } catch {
        /* 미완 무시 — WS 수신 대기 */
      }
    });
    return () => unsubs.forEach((u) => u());
  }, [previewJobIds, eventId]);

  /** 조감 이미지 생성 — 사용자가 버튼을 클릭할 때만 발행(쿼터 보호). */
  async function requestPreview(o: AutoLayoutOption) {
    if (previewBusy[o.optionId] || previewJobIds[o.optionId]) return;
    setPreviewBusy((prev) => ({ ...prev, [o.optionId]: true }));
    try {
      const res = await layoutApi.previewS7(eventId, selHall, o.label);
      if (res.jobId) {
        setPreviewJobIds((prev) => ({ ...prev, [o.optionId]: res.jobId as string }));
      } else {
        setError('이미지 생성 큐가 준비되지 않았습니다(렌더 인프라 점검 필요). 배치안 선택은 계속할 수 있습니다.');
      }
    } catch {
      setError('이미지 생성 요청에 실패했습니다. 잠시 후 다시 시도해 주세요.');
    } finally {
      setPreviewBusy((prev) => ({ ...prev, [o.optionId]: false }));
    }
  }

  async function generate() {
    setError(null);
    setPhase('generating');
    setRenderJobs({});
    setPreviewJobIds({});
    try {
      const res = await layoutApi.autoGenerate(
        eventId,
        selHall,
        { ...req, zoneId: selZone || null },
        true,
      );
      setOptions(res);
      setSelected(res[0]?.optionId ?? null);
      setPhase('result');
    } catch (err) {
      if (err instanceof ApiRequestError) {
        setError(
          err.code === 'NOT_IMPLEMENTED'
            ? 'AI 자동배치 엔진이 준비 중입니다(백엔드 매퍼 대기).'
            : err.message,
        );
      } else {
        setError('자동배치 생성 중 오류가 발생했습니다.');
      }
      setPhase('form');
    }
  }

  /** "이 안으로 편집 시작" — apply-option으로 서버에 새 배치안 버전 저장(실배선). */
  async function applySelected() {
    const option = options.find((o) => o.optionId === selected);
    if (!option || applying) return;
    setApplying(true);
    setError(null);
    try {
      await layoutApi.applyOption(eventId, selHall, {
        name: `${option.label}(적용)`,
        booths: option.booths,
      });
      onApply(option, selHall);
    } catch (err) {
      setError(
        err instanceof ApiRequestError
          ? `배치안 저장 실패: ${err.message}`
          : '배치안 저장 중 오류가 발생했습니다.',
      );
    } finally {
      setApplying(false);
    }
  }

  const steps: { key: Phase; label: string }[] = [
    { key: 'place', label: '① 어디에' },
    { key: 'form', label: '② 조건' },
    { key: 'result', label: '③ 배치안 선택' },
  ];
  const stepIndex = phase === 'place' ? 0 : phase === 'form' || phase === 'generating' ? 1 : 2;

  return (
    <div className="kx-modal" role="dialog" aria-modal="true" aria-labelledby="auto-title">
      <div className="kx-modal__backdrop" onClick={onClose} />
      <div className="kx-auto">
        <header className="kx-auto__header">
          <div>
            <h3 id="auto-title" className="kx-auto__title">
              <AiLabel>AI 자동배치</AiLabel> 평면도 안 자동 배치
            </h3>
            <p className="kx-auto__sub">
              전시장 평면도를 고르고 조건을 입력하면, 도면 바닥면 안에 배치안을 생성합니다.
            </p>
          </div>
          <button className="kx-auto__close" onClick={onClose} aria-label="닫기">
            ✕
          </button>
        </header>

        {/* 단계 표시 */}
        <ol className="kx-auto__steps" aria-label="진행 단계">
          {steps.map((s, i) => (
            <li key={s.key} className={i === stepIndex ? 'is-active' : i < stepIndex ? 'is-done' : ''}>
              {s.label}
            </li>
          ))}
        </ol>

        {phase === 'place' && (
          <div className="kx-auto__body">
            <div className="kx-auto__place">
              <div className="kx-field">
                <label htmlFor="auto-center">전시장 (대분류)</label>
                <select
                  id="auto-center"
                  className="kx-select"
                  value={activeCenter?.center ?? ''}
                  onChange={(e) => {
                    const c = centers.find((x) => x.center === Number(e.target.value));
                    setSelCenter(c?.center ?? null);
                    const first = c?.halls[0];
                    if (first) {
                      setSelHall(first.id);
                      setSelZone('');
                    }
                  }}
                >
                  {centers.map((c) => (
                    <option key={c.center} value={c.center}>
                      {c.label}
                    </option>
                  ))}
                </select>
              </div>
              <div className="kx-field">
                <label htmlFor="auto-hall">홀 (중분류)</label>
                <select
                  id="auto-hall"
                  className="kx-select"
                  value={selHall}
                  onChange={(e) => {
                    setSelHall(e.target.value);
                    setSelZone('');
                  }}
                >
                  {(activeCenter?.halls ?? []).map((h) => (
                    <option key={h.id} value={h.id}>
                      {h.label}
                      {h.dimsM.length >= 2 ? ` — ${h.dimsM[0]}×${h.dimsM[1]}m` : ''}
                    </option>
                  ))}
                </select>
              </div>
              <div className="kx-field">
                <label htmlFor="auto-zone">구역 (소분류)</label>
                <select
                  id="auto-zone"
                  className="kx-select"
                  value={selZone}
                  onChange={(e) => setSelZone(e.target.value)}
                >
                  <option value="">홀 전체</option>
                  {(activeHall?.zones ?? []).map((z) => (
                    <option key={z.id} value={z.id}>
                      {z.label} 구역
                    </option>
                  ))}
                </select>
              </div>
            </div>
            {treeQuery.isError && (
              <p className="kx-auto__nl-note is-degraded">⚠ 평면도 목록을 불러오지 못해 현재 홀({hallId}) 기준으로 진행합니다.</p>
            )}
            <div className="kx-modal__actions">
              <Button variant="ghost" onClick={onClose}>
                취소
              </Button>
              <Button onClick={() => setPhase('form')}>다음 — 조건 입력</Button>
            </div>
          </div>
        )}

        {phase === 'form' && (
          <div className="kx-auto__body">
            <div className="kx-auto__nl">
              <label className="kx-auto__nl-label" htmlFor="auto-nl">
                <AiLabel>WISE AI</AiLabel> 자연어로 조건 입력
              </label>
              <div className="kx-auto__nl-row">
                <input
                  id="auto-nl"
                  className="kx-auto__nl-input"
                  type="text"
                  value={nlText}
                  placeholder="예: 부스 120개, 프리미엄 3할, 무대 1개, 입구 2개로 3안 뽑아줘"
                  onChange={(e) => setNlText(e.target.value)}
                  onKeyDown={(e) => {
                    if (e.key === 'Enter') {
                      e.preventDefault();
                      interpret();
                    }
                  }}
                />
                <Button
                  variant="ai"
                  leadingIcon="✦"
                  onClick={interpret}
                  disabled={!nlText.trim() || interpreting}
                >
                  {interpreting ? '해석 중…' : 'AI 해석'}
                </Button>
              </div>
              {nlNote && (
                <p
                  className={`kx-auto__nl-note ${nlDegraded ? 'is-degraded' : ''}`}
                  aria-live="polite"
                >
                  {nlDegraded ? '⚠ ' : '✓ '}
                  {nlNote}
                  {!nlDegraded && ' 아래 값을 확인·수정한 뒤 생성하세요.'}
                </p>
              )}
            </div>
            <div className="kx-auto__form">
              <NumField
                label="목표 부스 수"
                value={req.targetBoothCount}
                onChange={(v) => setReq({ ...req, targetBoothCount: v })}
              />
              <NumField
                label="프리미엄 비율 (%)"
                value={Math.round(req.premiumRatio * 100)}
                onChange={(v) => setReq({ ...req, premiumRatio: v / 100 })}
              />
              <NumField
                label="무대 수"
                value={req.stageCount}
                onChange={(v) => setReq({ ...req, stageCount: v })}
              />
              <NumField
                label="주출입구 수"
                value={req.mainEntranceCount}
                onChange={(v) => setReq({ ...req, mainEntranceCount: v })}
              />
              <NumField
                label="생성 안 수"
                value={req.optionCount}
                onChange={(v) => setReq({ ...req, optionCount: Math.min(3, Math.max(1, v)) })}
              />
            </div>
            {error && <ErrorState message={error} onRetry={generate} />}
            <div className="kx-modal__actions">
              <Button variant="ghost" onClick={() => setPhase('place')}>
                ← 평면도 다시 선택
              </Button>
              <Button variant="ai" leadingIcon="✦" onClick={generate}>
                배치안 생성
              </Button>
            </div>
          </div>
        )}

        {phase === 'generating' && (
          <div className="kx-auto__generating" aria-live="polite">
            <span className="kx-aiimg__spinner" aria-hidden="true" />
            <p>제약조건 풀이 중… 복수 안 생성</p>
          </div>
        )}

        {phase === 'result' && (
          <div className="kx-auto__body">
            {error && <p className="kx-auto__nl-note is-degraded">⚠ {error}</p>}
            <div className="kx-auto__grid">
              {options.map((o) => {
                const job = renderJobs[o.optionId];
                const jobRequested = Boolean(previewJobIds[o.optionId]);
                const isSel = o.optionId === selected;
                return (
                  <label
                    key={o.optionId}
                    className={`kx-auto__card ${isSel ? 'is-selected' : ''}`}
                  >
                    <input
                      type="radio"
                      name="auto-option"
                      checked={isSel}
                      onChange={() => setSelected(o.optionId)}
                    />
                    {jobRequested ? (
                      <div
                        className={`kx-auto__imgwrap ${job?.imageUrl ? 'is-zoomable' : ''}`}
                        onClick={(e) => {
                          if (job?.imageUrl) {
                            e.preventDefault();
                            setLightbox({ url: job.imageUrl, alt: `${o.label} 조감` });
                          }
                        }}
                        title={job?.imageUrl ? '클릭하면 확대 이미지를 봅니다' : undefined}
                      >
                        <AiImage
                          imageUrl={job?.imageUrl ?? null}
                          status={job?.status ?? 'QUEUED'}
                          watermarkText={
                            job?.watermarkText ?? 'AI 생성 예상 이미지 — 실제 시공 결과와 다를 수 있습니다'
                          }
                          notice={
                            job?.notice ??
                            'AI 생성 이미지는 계약·심사 서류에 사용할 수 없습니다 — 시공 기준은 도면입니다'
                          }
                          shotLabel="S7 홀 전경"
                          alt={`${o.label} 조감`}
                        />
                      </div>
                    ) : (
                      <div className="kx-auto__imgcta">
                        <p>조감 이미지는 필요할 때만 생성합니다.</p>
                        <Button
                          variant="ai"
                          leadingIcon="🖼"
                          disabled={Boolean(previewBusy[o.optionId])}
                          onClick={(e) => {
                            e.preventDefault();
                            requestPreview(o);
                          }}
                        >
                          {previewBusy[o.optionId] ? '요청 중…' : '조감 이미지 생성'}
                        </Button>
                      </div>
                    )}
                    <div className="kx-auto__card-body">
                      <span className="kx-auto__card-title">{o.label}</span>
                      <ul className="kx-auto__metrics tnum">
                        <li>부스 {o.summary.boothCount} / {o.summary.targetBoothCount}</li>
                        <li>판매면적 {o.summary.salesAreaM2.toLocaleString()}㎡</li>
                        <li>최소 통로폭 {o.summary.minAisleWidthM}m</li>
                        <li
                          className={
                            o.summary.violationBlock > 0 ? 'kx-auto__viol-bad' : 'kx-auto__viol-ok'
                          }
                        >
                          위반 {o.summary.violationBlock + o.summary.violationWarn}건
                        </li>
                      </ul>
                      {o.aiSummary && (
                        <div className="kx-auto__ai-summary">
                          <AiLabel>WISE AI</AiLabel>
                          <p className="kx-auto__ai-summary-text">{o.aiSummary}</p>
                        </div>
                      )}
                    </div>
                  </label>
                );
              })}
            </div>
            <p className="kx-auto__keepnote">
              생성한 조감 이미지는 자동 저장되어 시각화 갤러리에서 다시 보거나 공사 옥션 참고
              이미지로 쓸 수 있습니다.
            </p>
            <div className="kx-modal__actions">
              <Button variant="ghost" onClick={() => setPhase('form')}>
                조건 수정
              </Button>
              <Button disabled={!selected || applying} onClick={applySelected}>
                {applying ? '저장 중…' : '이 안으로 편집 시작'}
              </Button>
            </div>
          </div>
        )}

        {/* 확대 이미지 팝업(라이트박스) — 클릭 확대 + 저장(다운로드) */}
        {lightbox && (
          <div
            className="kx-lightbox"
            role="dialog"
            aria-modal="true"
            aria-label={`${lightbox.alt} 확대 보기`}
            onClick={() => setLightbox(null)}
            onKeyDown={(e) => {
              if (e.key === 'Escape') setLightbox(null);
            }}
            tabIndex={-1}
          >
            <div className="kx-lightbox__inner" onClick={(e) => e.stopPropagation()}>
              <img src={lightbox.url} alt={lightbox.alt} />
              <p className="kx-lightbox__notice">
                AI 생성 예상 이미지 — 실제 시공 결과와 다를 수 있습니다. 계약·심사 서류에 사용 불가.
              </p>
              <div className="kx-lightbox__actions">
                <a className="kx-lightbox__download" href={lightbox.url} download>
                  이미지 저장
                </a>
                <Button variant="ghost" onClick={() => setLightbox(null)}>
                  닫기
                </Button>
              </div>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

function NumField({
  label,
  value,
  onChange,
}: {
  label: string;
  value: number;
  onChange: (v: number) => void;
}) {
  return (
    <div className="kx-field">
      <label>{label}</label>
      <input
        type="number"
        value={value}
        onChange={(e) => onChange(Number(e.target.value))}
        className="tnum"
      />
    </div>
  );
}
