/* =========================================================
   Fusion AI 데모 — 아이소메트릭 CAM 뷰포트 + 샘플 형상/결과 데이터
   exports(window): PARTS, CamViewport
   결과 수치는 샘플 형상 기준 예시값입니다.
   ========================================================= */
const A30 = Math.PI / 6;

/* ---------- 샘플 형상 + 연산 결과 데이터 ---------- */
const PARTS = {
  bracket: {
    key: "bracket", color: "#3A6EA5",
    name: "마운팅 브라켓", file: "mount_bracket_v3.step",
    material: "AL 6061-T6", size: "120 × 80 × 25 mm", stock: "125 × 85 × 28 mm",
    faces: "12,480", features: "포켓 2 · 홀 8 · 윤곽 1",
    plate: { w: 120, d: 80, h: 25 }, scale: 4.0,
    pockets: [
      { x0: 16, y0: 14, x1: 58, y1: 66, depth: 11 },
      { x0: 72, y0: 22, x1: 104, y1: 58, depth: 8 },
    ],
    holes: [
      { x: 14, y: 12, r: 3.3 }, { x: 14, y: 40, r: 3.3 }, { x: 14, y: 68, r: 3.3 },
      { x: 64, y: 12, r: 3.3 }, { x: 64, y: 68, r: 3.3 },
      { x: 112, y: 12, r: 3.3 }, { x: 112, y: 40, r: 3.3 }, { x: 112, y: 68, r: 3.3 },
    ],
    operations: [
      { name: "정면 가공", strat: "Face", tool: "T1", time: "01:48", S: 8000, F: 3000, ap: "0.5", ae: "38", color: "#9AA0A6" },
      { name: "포켓 1 황삭", strat: "2D Adaptive", tool: "T2", time: "03:42", S: 10500, F: 3800, ap: "11", ae: "4.5", color: "#FD6F00" },
      { name: "포켓 1 정삭", strat: "Contour", tool: "T3", time: "02:10", S: 12000, F: 2600, ap: "11", ae: "0.3", color: "#FFB066" },
      { name: "포켓 2 황삭", strat: "2D Adaptive", tool: "T2", time: "02:26", S: 10500, F: 3800, ap: "8", ae: "4.5", color: "#FD6F00" },
      { name: "드릴링 8×Ø6.6", strat: "Drill", tool: "T4", time: "01:32", S: 4500, F: 450, ap: "28", ae: "—", color: "#5BC0BE" },
      { name: "외곽 모따기", strat: "2D Chamfer", tool: "T5", time: "00:54", S: 9000, F: 1800, ap: "1", ae: "—", color: "#C77DFF" },
    ],
    tools: [
      { id: "T1", type: "페이스밀", dia: "Ø50", flutes: 4, mat: "Carbide", S: 8000, F: 3000 },
      { id: "T2", type: "평 엔드밀", dia: "Ø10", flutes: 3, mat: "Carbide", S: 10500, F: 3800 },
      { id: "T3", type: "평 엔드밀", dia: "Ø6", flutes: 4, mat: "Carbide", S: 12000, F: 2600 },
      { id: "T4", type: "드릴", dia: "Ø6.6", flutes: 2, mat: "HSS-Co", S: 4500, F: 450 },
      { id: "T5", type: "챔퍼밀", dia: "Ø10·45°", flutes: 4, mat: "Carbide", S: 9000, F: 1800 },
    ],
    summary: { total: "12:32", ops: 6, tools: 5, removed: "34%" },
  },

  housing: {
    key: "housing", color: "#6B7280",
    name: "기어 하우징", file: "gear_housing.iges",
    material: "SCM440", size: "90 × 90 × 30 mm", stock: "94 × 94 × 32 mm",
    faces: "9,210", features: "보어 1 · 포켓 1 · 홀 4",
    plate: { w: 90, d: 90, h: 30 }, scale: 4.6,
    pockets: [{ x0: 18, y0: 18, x1: 72, y1: 72, depth: 16 }],
    holes: [
      { x: 10, y: 10, r: 4 }, { x: 80, y: 10, r: 4 }, { x: 10, y: 80, r: 4 }, { x: 80, y: 80, r: 4 },
      { x: 45, y: 45, r: 13 },
    ],
    operations: [
      { name: "정면 가공", strat: "Face", tool: "T1", time: "02:36", S: 1200, F: 600, ap: "0.4", ae: "30", color: "#9AA0A6" },
      { name: "포켓 황삭", strat: "2D Adaptive", tool: "T2", time: "08:14", S: 2200, F: 720, ap: "16", ae: "3.2", color: "#FD6F00" },
      { name: "포켓 정삭", strat: "Contour", tool: "T3", time: "04:48", S: 2800, F: 540, ap: "16", ae: "0.2", color: "#FFB066" },
      { name: "보어 드릴 Ø26", strat: "Bore", tool: "T4", time: "03:20", S: 900, F: 90, ap: "30", ae: "—", color: "#5BC0BE" },
      { name: "탭 홀 4×M8", strat: "Drill", tool: "T5", time: "02:05", S: 1100, F: 140, ap: "20", ae: "—", color: "#5BC0BE" },
    ],
    tools: [
      { id: "T1", type: "페이스밀", dia: "Ø63", flutes: 5, mat: "Carbide", S: 1200, F: 600 },
      { id: "T2", type: "평 엔드밀", dia: "Ø12", flutes: 4, mat: "Carbide", S: 2200, F: 720 },
      { id: "T3", type: "평 엔드밀", dia: "Ø8", flutes: 4, mat: "Carbide", S: 2800, F: 540 },
      { id: "T4", type: "보어드릴", dia: "Ø26", flutes: 2, mat: "Carbide", S: 900, F: 90 },
      { id: "T5", type: "드릴", dia: "Ø6.8", flutes: 2, mat: "HSS-Co", S: 1100, F: 140 },
    ],
    summary: { total: "21:03", ops: 5, tools: 5, removed: "41%" },
  },

  core: {
    key: "core", color: "#8A5A44",
    name: "몰드 코어", file: "mold_core_a.stp",
    material: "STAVAX (STAINLESS)", size: "100 × 70 × 35 mm", stock: "104 × 74 × 38 mm",
    faces: "18,640", features: "곡면 1 · 단차 2 · 윤곽 1",
    plate: { w: 100, d: 70, h: 35 }, scale: 4.4,
    pockets: [
      { x0: 12, y0: 12, x1: 88, y1: 40, depth: 20 },
      { x0: 30, y0: 44, x1: 70, y1: 60, depth: 10 },
    ],
    holes: [],
    operations: [
      { name: "정면 가공", strat: "Face", tool: "T1", time: "02:10", S: 3000, F: 800, ap: "0.5", ae: "32", color: "#9AA0A6" },
      { name: "황삭", strat: "3D Adaptive", tool: "T2", time: "11:28", S: 4200, F: 1100, ap: "20", ae: "3.6", color: "#FD6F00" },
      { name: "중삭", strat: "Parallel", tool: "T3", time: "06:54", S: 6000, F: 1400, ap: "0.4", ae: "0.6", color: "#FFB066" },
      { name: "정삭", strat: "Scallop", tool: "T4", time: "09:40", S: 8500, F: 1600, ap: "0.15", ae: "0.2", color: "#C77DFF" },
    ],
    tools: [
      { id: "T1", type: "페이스밀", dia: "Ø50", flutes: 4, mat: "Carbide", S: 3000, F: 800 },
      { id: "T2", type: "불 엔드밀", dia: "Ø10 R1", flutes: 4, mat: "Carbide", S: 4200, F: 1100 },
      { id: "T3", type: "볼 엔드밀", dia: "Ø6 R3", flutes: 2, mat: "Carbide", S: 6000, F: 1400 },
      { id: "T4", type: "볼 엔드밀", dia: "Ø4 R2", flutes: 2, mat: "Carbide", S: 8500, F: 1600 },
    ],
    summary: { total: "30:12", ops: 4, tools: 4, removed: "38%" },
  },
};

/* ---------- 아이소메트릭 투영 ---------- */
function makeProjector(part) {
  const { w, d, h } = part.plate;
  const s = part.scale || 4;
  const raw = (x, y, z) => [(x - y) * Math.cos(A30) * s, ((x + y) * Math.sin(A30) - z) * s];
  const corners = [
    [0, 0, 0], [w, 0, 0], [w, d, 0], [0, d, 0],
    [0, 0, h], [w, 0, h], [w, d, h], [0, d, h],
  ].map((c) => raw(c[0], c[1], c[2]));
  const xs = corners.map((c) => c[0]), ys = corners.map((c) => c[1]);
  const ox = 450 - (Math.min(...xs) + Math.max(...xs)) / 2;
  const oy = 312 - (Math.min(...ys) + Math.max(...ys)) / 2;
  return (x, y, z) => { const [px, py] = raw(x, y, z); return [px + ox, py + oy]; };
}
const ptStr = (p) => p[0].toFixed(1) + "," + p[1].toFixed(1);
const poly = (proj, pts) => pts.map((c) => ptStr(proj(c[0], c[1], c[2]))).join(" ");
function lineD(proj, pts) {
  return pts.map((c, i) => (i ? "L" : "M") + ptStr(proj(c[0], c[1], c[2]))).join(" ");
}

/* ---------- 테마 팔레트 ---------- */
function camPal(theme) {
  if (theme === "light") return {
    top: "#E7EAEE", right: "#CFD4DB", left: "#BFC5CD",
    floor: "#ADB3BC", wallA: "#C6CBD2", wallB: "#BCC2CA",
    edge: "rgba(10,10,10,0.22)", rim: "rgba(10,10,10,0.30)", pocket: "rgba(10,10,10,0.12)",
    holeFill: "#9AA0A8", holeStroke: "rgba(10,10,10,0.34)",
  };
  return {
    top: "#26262C", right: "#1A1A1F", left: "#141417",
    floor: "#0E0E11", wallA: "#17171C", wallB: "#1C1C22",
    edge: "rgba(255,255,255,0.16)", rim: "rgba(255,255,255,0.22)", pocket: "rgba(255,255,255,0.10)",
    holeFill: "#08080A", holeStroke: "rgba(255,255,255,0.3)",
  };
}

/* ---------- 형상 면 빌드 ---------- */
function buildShape(part, proj, P) {
  const { w, d, h } = part.plate;
  const faces = [
    { cls: "top", pts: [[0, 0, h], [w, 0, h], [w, d, h], [0, d, h]], fill: P.top },
    { cls: "right", pts: [[w, 0, 0], [w, d, 0], [w, d, h], [w, 0, h]], fill: P.right },
    { cls: "left", pts: [[0, d, 0], [w, d, 0], [w, d, h], [0, d, h]], fill: P.left },
  ];
  const pocketEls = [];
  part.pockets.forEach((pk) => {
    const zf = h - pk.depth;
    pocketEls.push({ type: "floor", pts: [[pk.x0, pk.y0, zf], [pk.x1, pk.y0, zf], [pk.x1, pk.y1, zf], [pk.x0, pk.y1, zf]], fill: P.floor });
    pocketEls.push({ type: "wall", pts: [[pk.x0, pk.y0, h], [pk.x1, pk.y0, h], [pk.x1, pk.y0, zf], [pk.x0, pk.y0, zf]], fill: P.wallA });
    pocketEls.push({ type: "wall", pts: [[pk.x0, pk.y0, h], [pk.x0, pk.y1, h], [pk.x0, pk.y1, zf], [pk.x0, pk.y0, zf]], fill: P.wallB });
    pocketEls.push({ type: "rim", pts: [[pk.x0, pk.y0, h], [pk.x1, pk.y0, h], [pk.x1, pk.y1, h], [pk.x0, pk.y1, h]] });
  });
  const holeEls = part.holes.map((ho) => {
    const c = proj(ho.x, ho.y, h);
    return { cx: c[0], cy: c[1], rx: ho.r * (part.scale || 4) * Math.cos(A30), ry: ho.r * (part.scale || 4) * Math.sin(A30) };
  });
  return { faces, pocketEls, holeEls };
}

/* ---------- 툴패스 생성 (operation 순서와 1:1) ---------- */
function zig(x0, y0, x1, y1, z, step) {
  const pts = []; let dir = 1;
  for (let y = y0; y <= y1 + 0.01; y += step) {
    if (dir > 0) { pts.push([x0, y, z]); pts.push([x1, y, z]); }
    else { pts.push([x1, y, z]); pts.push([x0, y, z]); }
    dir *= -1;
  }
  return pts;
}
function rect(x0, y0, x1, y1, z) { return [[x0, y0, z], [x1, y0, z], [x1, y1, z], [x0, y1, z], [x0, y0, z]]; }

function buildToolpaths(part, proj) {
  const { w, d, h } = part.plate;
  const out = [];
  const ins = 4; // 공구 반경 인셋 근사
  // 1. 정면
  out.push({ d: lineD(proj, zig(3, 5, w - 3, d - 5, h + 0.4, 9)) });
  // 각 포켓: 황삭(지그재그) + 정삭(윤곽) — core는 곡면이라 별도지만 동일 패턴으로 근사
  part.pockets.forEach((pk, i) => {
    const zf = h - pk.depth;
    out.push({ d: lineD(proj, zig(pk.x0 + ins, pk.y0 + ins, pk.x1 - ins, pk.y1 - ins, zf, 6)) });
    if (i === 0 || part.key === "bracket") {
      out.push({ d: lineD(proj, rect(pk.x0 + 1, pk.y0 + 1, pk.x1 - 1, pk.y1 - 1, zf)) });
    }
  });
  // 드릴링: 홀 상단 짧은 수직 마크 + 래피드 연결
  if (part.holes.length) {
    let dd = "";
    part.holes.forEach((ho) => {
      const a = proj(ho.x, ho.y, h + 1), b = proj(ho.x, ho.y, h - Math.min(part.plate.h, 14));
      dd += "M" + ptStr(a) + "L" + ptStr(b) + " ";
    });
    out.push({ d: dd.trim(), drill: true });
  }
  // 마지막: 외곽 윤곽/모따기
  out.push({ d: lineD(proj, rect(2, 2, w - 2, d - 2, h)) });
  return out;
}

/* ---------- React 뷰포트 ---------- */
const { useRef, useEffect, useMemo, useState } = React;

function CamViewport({ part, phase, drawnCount, activeIndex, activeDur, onActiveDone, highlightOp, theme }) {
  const P = useMemo(() => camPal(theme), [theme]);
  const proj = useMemo(() => (part ? makeProjector(part) : null), [part]);
  const shape = useMemo(() => (part && proj ? buildShape(part, proj, P) : null), [part, proj, P]);
  const paths = useMemo(() => (part && proj ? buildToolpaths(part, proj) : []), [part, proj]);

  const activeRef = useRef(null);
  const toolRef = useRef(null);
  const rafRef = useRef(0);

  // active op draw + tool marker animation
  useEffect(() => {
    if (phase !== "computing" || activeIndex == null || !paths[activeIndex]) return;
    const pathEl = activeRef.current;
    if (!pathEl) return;
    const len = pathEl.getTotalLength();
    pathEl.style.transition = "none";
    pathEl.style.strokeDasharray = len;
    pathEl.style.strokeDashoffset = len;
    // force reflow then animate
    void pathEl.getBoundingClientRect();
    requestAnimationFrame(() => {
      pathEl.style.transition = `stroke-dashoffset ${activeDur}ms linear`;
      pathEl.style.strokeDashoffset = "0";
    });
    // tool marker along path
    const start = performance.now();
    const tick = (now) => {
      const t = Math.min(1, (now - start) / activeDur);
      if (toolRef.current) {
        const pt = pathEl.getPointAtLength(t * len);
        toolRef.current.setAttribute("transform", `translate(${pt.x.toFixed(1)} ${pt.y.toFixed(1)})`);
      }
      if (t < 1) rafRef.current = requestAnimationFrame(tick);
      else if (onActiveDone) onActiveDone();
    };
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
    // eslint-disable-next-line
  }, [phase, activeIndex, activeDur]);

  if (!part || !shape) {
    return (
      <svg viewBox="0 0 900 624" preserveAspectRatio="xMidYMid meet" aria-hidden="true"></svg>
    );
  }

  const showAll = phase === "done";
  const drawnEls = [];
  const upTo = showAll ? paths.length : drawnCount;
  for (let i = 0; i < upTo; i++) {
    if (i === activeIndex && phase === "computing") continue;
    const op = part.operations[i];
    const dim = highlightOp != null && highlightOp !== i;
    drawnEls.push(
      <path key={"p" + i} d={paths[i].d}
        className={"cam-path" + (paths[i].drill ? " rapid" : "")}
        style={{
          stroke: paths[i].drill ? undefined : (op ? op.color : undefined),
          opacity: dim ? 0.12 : 1,
          filter: dim ? "none" : undefined,
        }} />
    );
  }

  return (
    <svg viewBox="0 0 900 624" preserveAspectRatio="xMidYMid meet">
      {/* faces */}
      {shape.faces.map((f, i) => (
        <polygon key={"f" + i} points={poly(proj, f.pts)} fill={f.fill} stroke={P.edge} strokeWidth="1" />
      ))}
      {/* pockets */}
      {shape.pocketEls.map((p, i) =>
        p.type === "rim"
          ? <polygon key={"pk" + i} points={poly(proj, p.pts)} fill="none" stroke={P.rim} strokeWidth="1" />
          : <polygon key={"pk" + i} points={poly(proj, p.pts)} fill={p.fill} stroke={P.pocket} strokeWidth="0.75" />
      )}
      {/* holes */}
      {shape.holeEls.map((ho, i) => (
        <ellipse key={"h" + i} cx={ho.cx} cy={ho.cy} rx={ho.rx} ry={ho.ry} fill={P.holeFill} stroke={P.holeStroke} strokeWidth="1" />
      ))}
      {/* drawn toolpaths */}
      {(phase === "computing" || phase === "done") && drawnEls}
      {/* active op being drawn */}
      {phase === "computing" && activeIndex != null && paths[activeIndex] && (
        <path ref={activeRef} d={paths[activeIndex].d}
          className={"cam-path" + (paths[activeIndex].drill ? " rapid" : "")}
          style={{ stroke: paths[activeIndex].drill ? undefined : (part.operations[activeIndex] ? part.operations[activeIndex].color : undefined) }} />
      )}
      {/* tool marker */}
      {phase === "computing" && activeIndex != null && (
        <g ref={toolRef} className="cam-tool-grp">
          <line className="cam-tool-axis" x1="0" y1="0" x2="0" y2="-46" />
          <circle className="cam-tool" cx="0" cy="0" r="5" />
          <circle cx="0" cy="0" r="9" fill="none" stroke="var(--accent)" strokeWidth="1" opacity="0.5" />
        </g>
      )}
    </svg>
  );
}

window.PARTS = PARTS;
window.CamViewport = CamViewport;
