import { useEffect, useMemo, useRef, useState } from 'react';
import type { BoothDto, HallObstacleDto, HallPillarDto, HallTrenchDto } from '../../api/types';
import './canvas.css';

const ZOOM_MIN = 0.3;
const ZOOM_MAX = 4;
const WHEEL_STEP = 1.1;
const DRAG_THRESHOLD_PX = 3;

/*
 * 플로어플랜 SVG 캔버스 (SCR-03 히어로).
 * - 다크 서피스(#1C2536) 위 부스 폴리곤 + 트렌치 그리드 + 위반 오버레이.
 * - 좌표계: 홀 로컬 미터 → SVG 유저 유닛(1m = 1unit), viewBox로 스케일.
 * - 대규모(수백 부스)는 후속 WebGL/Canvas 검토. 지금은 SVG 우선.
 */

export interface CanvasLayer {
  trench: boolean;
  structure: boolean;
  violations: boolean;
}

interface FloorplanCanvasProps {
  hallDims: [number, number]; // [width_m, height_m]
  booths: BoothDto[];
  layers: CanvasLayer;
  selectedBoothId: string | null;
  onSelectBooth: (boothId: string | null) => void;
  zoom: number;
  /** 실측 홀 도면(크롤 JPG) 언더레이 URL — 없거나 로드 실패 시 기존 다크 서피스만. */
  floorplanUrl?: string | null;
  /**
   * 도면 이미지 내 전시 바닥면 분율 영역 [x0,y0,x1,y1] (hallFloorplan.ts 캘리브레이션).
   * 지정 시 이 영역이 홀 사각형(0,0~hw,hh)에 정렬되도록 이미지를 확대 배치 —
   * 부스 좌표(홀 로컬 m)가 도면의 채색 바닥면 "안"에 놓인다. 미지정 시 전체 스트레치(구 동작).
   */
  floorRegion?: [number, number, number, number] | null;
  /** 마우스휠 확대/축소 시 페이지 zoom 상태 동기화(소유자 지시 2026-07-14). 미지정 시 휠 줌 비활성. */
  onZoomChange?: (zoom: number) => void;
  /** 홀 기둥(V62 실측) — 구조 레이어에 원으로 표시(자동배치는 서버가 회피). */
  pillars?: HallPillarDto[] | null;
  /** 벽·계단·엘리베이터·문 장애물(V63 실측) — 구조 레이어에 사각으로 표시. */
  obstacles?: HallObstacleDto[] | null;
  /** 트렌치 공급 포인트(V61/V65) — 있으면 실데이터 도트, 없으면 합성 9m 그리드 폴백. */
  trenches?: HallTrenchDto[] | null;
}

const TRENCH_SPACING_M = 9; // 가정 트렌치 그리드 간격(실측 대체 — R4)
const PAD = 6; // viewBox 여백(m)

function centroid(poly: number[][]): [number, number] {
  const n = poly.length;
  let x = 0;
  let y = 0;
  for (const [px, py] of poly) {
    x += px;
    y += py;
  }
  return [x / n, y / n];
}

export function FloorplanCanvas({
  hallDims,
  booths,
  layers,
  selectedBoothId,
  onSelectBooth,
  zoom,
  floorplanUrl,
  floorRegion,
  onZoomChange,
  pillars,
  obstacles,
  trenches,
}: FloorplanCanvasProps) {
  const [hw, hh] = hallDims;

  // 도면 배치: 캘리브레이션 영역이 있으면 바닥면(fx0..fx1, fy0..fy1)이 홀 사각형에 오도록 역산.
  const drawing = useMemo(() => {
    if (!floorRegion) {
      return { x: 0, y: 0, w: hw, h: hh, clipped: false };
    }
    const [fx0, fy0, fx1, fy1] = floorRegion;
    const rw = fx1 - fx0;
    const rh = fy1 - fy0;
    if (rw <= 0 || rh <= 0) {
      return { x: 0, y: 0, w: hw, h: hh, clipped: false };
    }
    const w = hw / rw;
    const h = hh / rh;
    return { x: -fx0 * w, y: -fy0 * h, w, h, clipped: true };
  }, [floorRegion, hw, hh]);
  const [drawingOk, setDrawingOk] = useState(true);
  useEffect(() => setDrawingOk(true), [floorplanUrl]);

  // ── 뷰어 조작(소유자 지시 2026-07-14): 마우스휠 확대/축소 + 왼쪽 드래그 이동 ──
  const rootRef = useRef<HTMLDivElement | null>(null);
  const [pan, setPan] = useState({ x: 0, y: 0 });
  const [panning, setPanning] = useState(false);
  const dragRef = useRef<{ startX: number; startY: number; baseX: number; baseY: number; moved: boolean } | null>(null);
  const zoomRef = useRef(zoom);
  zoomRef.current = zoom;

  // 휠 줌 — 페이지 스크롤 억제를 위해 non-passive 리스너로 직접 부착.
  useEffect(() => {
    const el = rootRef.current;
    if (!el || !onZoomChange) return;
    const onWheel = (e: WheelEvent) => {
      e.preventDefault();
      const factor = e.deltaY < 0 ? WHEEL_STEP : 1 / WHEEL_STEP;
      const next = Math.min(ZOOM_MAX, Math.max(ZOOM_MIN, zoomRef.current * factor));
      onZoomChange(Math.round(next * 100) / 100);
    };
    el.addEventListener('wheel', onWheel, { passive: false });
    return () => el.removeEventListener('wheel', onWheel);
  }, [onZoomChange]);

  const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
    if (e.button !== 0) return; // 왼쪽 버튼만 이동
    dragRef.current = { startX: e.clientX, startY: e.clientY, baseX: pan.x, baseY: pan.y, moved: false };
    (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);
  };
  const onPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {
    const d = dragRef.current;
    if (!d) return;
    const dx = e.clientX - d.startX;
    const dy = e.clientY - d.startY;
    if (!d.moved && Math.abs(dx) + Math.abs(dy) > DRAG_THRESHOLD_PX) {
      d.moved = true;
      setPanning(true);
    }
    if (d.moved) {
      setPan({ x: d.baseX + dx, y: d.baseY + dy });
    }
  };
  const endDrag = (e: React.PointerEvent<HTMLDivElement>) => {
    if (dragRef.current) {
      try {
        (e.currentTarget as HTMLDivElement).releasePointerCapture(e.pointerId);
      } catch {
        /* 캡처 미보유 무시 */
      }
    }
    setPanning(false);
    // moved 플래그는 클릭 억제 판정(onClickCapture)까지 유지 — 클릭 이벤트가 뒤따라 온다.
  };
  // 드래그 직후 따라오는 click이 부스 선택/해제를 오발하지 않게 캡처 단계에서 차단.
  const onClickCapture = (e: React.MouseEvent<HTMLDivElement>) => {
    if (dragRef.current?.moved) {
      e.preventDefault();
      e.stopPropagation();
    }
    dragRef.current = null;
  };

  const trenchLines = useMemo(() => {
    const lines: { x1: number; y1: number; x2: number; y2: number }[] = [];
    for (let x = TRENCH_SPACING_M; x < hw; x += TRENCH_SPACING_M) {
      lines.push({ x1: x, y1: 0, x2: x, y2: hh });
    }
    for (let y = TRENCH_SPACING_M; y < hh; y += TRENCH_SPACING_M) {
      lines.push({ x1: 0, y1: y, x2: hw, y2: y });
    }
    return lines;
  }, [hw, hh]);

  return (
    <div
      ref={rootRef}
      className={`kx-canvas ${panning ? 'is-panning' : ''}`}
      style={{ transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})` }}
      onPointerDown={onPointerDown}
      onPointerMove={onPointerMove}
      onPointerUp={endDrag}
      onPointerCancel={endDrag}
      onClickCapture={onClickCapture}
    >
      <svg
        className="kx-canvas__svg"
        viewBox={`${-PAD} ${-PAD} ${hw + PAD * 2} ${hh + PAD * 2}`}
        role="img"
        aria-label={`홀 도면 ${hw}×${hh}m, 부스 ${booths.length}개`}
        onClick={() => onSelectBooth(null)}
      >
        {/* 홀 외곽 */}
        <rect
          x={0}
          y={0}
          width={hw}
          height={hh}
          className="kx-canvas__hall"
          rx={0.5}
        />

        {/* 실측 홀 도면 언더레이(크롤 JPG) — 부스/트렌치 아래, 클릭 통과 */}
        {floorplanUrl && drawingOk && (
          <image
            href={floorplanUrl}
            x={drawing.x}
            y={drawing.y}
            width={drawing.w}
            height={drawing.h}
            preserveAspectRatio="none"
            className="kx-canvas__drawing"
            onError={() => setDrawingOk(false)}
          />
        )}

        {/* 벽·계단·엘리베이터·문 장애물(V63 실측) — 구조 레이어 */}
        {layers.structure && obstacles && obstacles.length > 0 && (
          <g className="kx-canvas__obstacles" aria-hidden="true">
            {obstacles.map((o) => (
              <rect
                key={o.obstacleId}
                className={`is-${o.kind}`}
                x={o.x0}
                y={o.y0}
                width={o.x1 - o.x0}
                height={o.y1 - o.y0}
              />
            ))}
          </g>
        )}

        {/* 기둥(V62 실측) — 구조 레이어 */}
        {layers.structure && pillars && pillars.length > 0 && (
          <g className="kx-canvas__pillars" aria-hidden="true">
            {pillars.map((p) => (
              <circle key={p.pillarId} cx={p.x} cy={p.y} r={Math.max(p.radiusM, 0.6)} />
            ))}
          </g>
        )}

        {/* 트렌치 — DB 실데이터(공급 포인트 도트) 우선, 없으면 합성 9m 그리드 폴백 */}
        {layers.trench &&
          (trenches && trenches.length > 0 ? (
            <g className="kx-canvas__trench-points" aria-hidden="true">
              {trenches.map((t) => (
                <circle key={t.trenchId} cx={t.x} cy={t.y} r={0.5}>
                  <title>{`${t.trenchId} — ${t.supplies.join('/')}`}</title>
                </circle>
              ))}
            </g>
          ) : (
            <g className="kx-canvas__trench">
              {trenchLines.map((l, i) => (
                <line key={i} x1={l.x1} y1={l.y1} x2={l.x2} y2={l.y2} />
              ))}
            </g>
          ))}

        {/* 부스 폴리곤 */}
        <g className="kx-canvas__booths">
          {booths.map((b) => {
            const pts = b.polygon.map(([x, y]) => `${x},${y}`).join(' ');
            const [cx, cy] = centroid(b.polygon);
            const selected = b.boothId === selectedBoothId;
            return (
              <g
                key={b.boothId}
                className={`kx-canvas__booth ${b.premium ? 'is-premium' : ''} ${
                  selected ? 'is-selected' : ''
                }`}
                onClick={(e) => {
                  e.stopPropagation();
                  onSelectBooth(b.boothId);
                }}
                tabIndex={0}
                role="button"
                aria-label={`부스 ${b.boothNo}${b.assignedCompanyName ? `, ${b.assignedCompanyName}` : ''}`}
                onKeyDown={(e) => {
                  if (e.key === 'Enter' || e.key === ' ') {
                    e.preventDefault();
                    onSelectBooth(b.boothId);
                  }
                }}
              >
                <polygon points={pts} />
                <text x={cx} y={cy} className="kx-canvas__booth-label">
                  {b.boothNo}
                </text>
              </g>
            );
          })}
        </g>

        {/* 축척 눈금 (상단) */}
        <g className="kx-canvas__ruler" aria-hidden="true">
          <line x1={0} y1={-2} x2={hw} y2={-2} />
          <text x={0} y={-3}>0m</text>
          <text x={hw / 2} y={-3} textAnchor="middle">{Math.round(hw / 2)}m</text>
          <text x={hw} y={-3} textAnchor="end">{hw}m</text>
        </g>
      </svg>
    </div>
  );
}
