/* 3D Persona Map Viewer
   Visualizes brand-specific personas as glowing nodes orbiting in 3D space.
   - X axis: age (young → old)
   - Y axis: gender skew (M → F)
   - Z axis: reach scale (niche → mass)
   - Sphere size: reach
   - Sphere color: validity score
   - Edges: shared categories
   Drag to orbit; auto-rotate; click node to inspect.
*/

const { useState: useP3State, useEffect: useP3Effect, useRef: useP3Ref, useMemo: useP3Memo } = React;

function PersonaMap3D({ personas, height = 480, onSelect }) {
  const stageRef = useP3Ref(null);
  const sceneRef = useP3Ref(null);
  const stateRef = useP3Ref({ rX: 18, rY: 28, autoRotate: true });
  const [selectedId, setSelectedId] = useP3State(null);
  const [, force] = useP3State(0);

  // Project persona stats → 3D position
  const nodes = useP3Memo(() => {
    if (!personas?.length) return [];
    const SE = window.SimEngine;
    const reaches = personas.map(p => p.result?.finalReach || 0);
    const maxReach = Math.max(1, ...reaches);
    return personas.map((p, i) => {
      const r = p.result;
      const ageMean = r?.ageDist ? r.ageDist.reduce((a, v, i) => a + v * i, 0) / r.ageDist.reduce((a, v) => a + v, 0) : 4;
      // age 0-8 → -1..1
      const x = (ageMean / 8) * 2 - 1;
      // gender skew 0..1 → -1..1 (F top)
      const y = -((r?.skew ?? 0.5) * 2 - 1);
      // reach → -1..1
      const z = (r?.finalReach || 0) / maxReach * 2 - 1;
      const size = 18 + Math.sqrt((r?.finalReach || 1) / maxReach) * 50;
      const validity = r?.validity ?? 50;
      return {
        id: p.id || `n${i}`,
        name: p.name,
        x: x * 160,
        y: y * 110,
        z: z * 140,
        size,
        validity,
        result: r,
        meta: p,
      };
    });
  }, [personas]);

  // Edges between nodes that share archetype dominance
  const edges = useP3Memo(() => {
    const out = [];
    for (let i = 0; i < nodes.length; i++) {
      for (let j = i + 1; j < nodes.length; j++) {
        const a = nodes[i], b = nodes[j];
        const d = Math.hypot(a.x - b.x, a.y - b.y, a.z - b.z);
        if (d < 180) out.push({ a, b, strength: 1 - d / 180 });
      }
    }
    return out;
  }, [nodes]);

  // Apply rotation to scene
  function apply() {
    if (sceneRef.current) {
      sceneRef.current.style.transform =
        `rotateX(${stateRef.current.rX}deg) rotateY(${stateRef.current.rY}deg)`;
    }
  }
  useP3Effect(() => {
    let raf, t0 = performance.now();
    function frame(now) {
      const dt = (now - t0) / 1000; t0 = now;
      if (stateRef.current.autoRotate) {
        stateRef.current.rY = (stateRef.current.rY + dt * 10) % 360;
        apply();
      }
      raf = requestAnimationFrame(frame);
    }
    raf = requestAnimationFrame(frame);
    apply();
    return () => cancelAnimationFrame(raf);
  }, []);

  function onPointerDown(e) {
    if (e.target.closest('.pm3-controls')) return;
    if (e.target.closest('.pm3-node')) return;
    stateRef.current.autoRotate = false;
    force(x => x + 1);
    const start = { x: e.clientX, y: e.clientY, rX: stateRef.current.rX, rY: stateRef.current.rY };
    const move = (ev) => {
      stateRef.current.rY = start.rY + (ev.clientX - start.x) * 0.4;
      stateRef.current.rX = Math.max(-60, Math.min(80, start.rX - (ev.clientY - start.y) * 0.4));
      apply();
    };
    const up = () => {
      window.removeEventListener('pointermove', move);
      window.removeEventListener('pointerup', up);
    };
    window.addEventListener('pointermove', move);
    window.addEventListener('pointerup', up);
  }

  function reset() {
    stateRef.current.rX = 18;
    stateRef.current.rY = 28;
    apply();
    force(x => x + 1);
  }
  function toggleRotate() {
    stateRef.current.autoRotate = !stateRef.current.autoRotate;
    force(x => x + 1);
  }

  if (!nodes.length) {
    return (
      <div className="pm3-empty" style={{ height }}>
        <div style={{ textAlign: 'center', color: 'var(--text-mute)' }}>
          <div style={{ fontSize: 14, marginBottom: 6 }}>표시할 페르소나가 없습니다</div>
          <div style={{ fontSize: 11 }}>브랜드를 분석하면 자동으로 페르소나가 생성됩니다</div>
        </div>
      </div>
    );
  }

  const selected = selectedId ? nodes.find(n => n.id === selectedId) : null;

  return (
    <div className="pm3-wrap" style={{ height }} ref={stageRef} onPointerDown={onPointerDown}>
      {/* Floor / horizon */}
      <div className="pm3-stage">
        <div className="pm3-scene" ref={sceneRef}>
          {/* Axis indicators */}
          <Axis pos={[0, 0, 0]} />
          {/* Grid floor */}
          <div className="pm3-floor" />
          {/* Edges */}
          <svg className="pm3-edges" viewBox="-300 -200 600 400">
            {edges.map((e, i) => (
              <line key={i}
                x1={e.a.x} y1={-e.a.y}
                x2={e.b.x} y2={-e.b.y}
                stroke={`oklch(0.80 0.14 72 / ${e.strength * 0.5})`}
                strokeWidth={0.5 + e.strength}
              />
            ))}
          </svg>
          {/* Nodes */}
          {nodes.map(n => (
            <PersonaNode key={n.id}
              node={n}
              selected={n.id === selectedId}
              onClick={() => { setSelectedId(n.id); onSelect?.(n); }}
            />
          ))}
        </div>
      </div>

      {/* Controls */}
      <div className="pm3-controls">
        <span className="label" style={{ color: 'var(--signal)' }}>3D 페르소나 맵</span>
        <button className="btn" data-size="sm" data-variant="ghost" onClick={toggleRotate}>
          {stateRef.current.autoRotate ? '⏸ 정지' : '▶ 회전'}
        </button>
        <button className="btn" data-size="sm" data-variant="ghost" onClick={reset}>↺ 리셋</button>
        <span className="mute" style={{ fontSize: 10, marginLeft: 'auto' }}>
          드래그로 시점 변경 · {nodes.length}개 노드
        </span>
      </div>

      {/* Axis legend */}
      <div className="pm3-legend">
        <span><span style={{ color: 'var(--signal)' }}>X</span> 연령</span>
        <span><span style={{ color: 'var(--cyan)' }}>Y</span> 성별스큐</span>
        <span><span style={{ color: 'var(--plant)' }}>Z</span> 도달규모</span>
      </div>

      {/* Detail panel */}
      {selected && (
        <div className="pm3-detail">
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <strong style={{ fontSize: 14 }}>{selected.name}</strong>
            <button className="btn" data-size="sm" data-variant="ghost"
                    onClick={() => setSelectedId(null)}>✕</button>
          </div>
          {selected.result && (
            <div style={{ marginTop: 8, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, fontSize: 11 }}>
              <Stat label="예상 도달" v={window.SimEngine.fmtN(selected.result.finalReach)} tone="cyan"/>
              <Stat label="클릭률" v={selected.result.ctr + '%'} tone="signal"/>
              <Stat label="타겟 정확도" v={selected.result.validity + '점'} tone="plant"/>
              <Stat label="경쟁도" v={selected.result.compete + '점'} tone="" />
              <Stat label="여성 비율" v={Math.round(selected.result.skew*100) + '%'} tone=""/>
              <Stat label="월 지출" v={window.SimEngine.fmtKRW(selected.result.budget)} tone=""/>
            </div>
          )}
        </div>
      )}

      <style>{`
        .pm3-wrap {
          position: relative;
          background: radial-gradient(ellipse at center,
            oklch(0.16 0.04 240 / 0.6) 0%,
            oklch(0.08 0.02 240 / 0.85) 70%);
          border: 1px solid rgba(255,240,220,0.08);
          overflow: hidden;
          user-select: none;
          touch-action: none;
        }
        .pm3-stage {
          position: absolute;
          inset: 0;
          perspective: 1800px;
          perspective-origin: 50% 50%;
          display: grid; place-items: center;
        }
        .pm3-scene {
          position: relative;
          transform-style: preserve-3d;
          width: 0; height: 0;
          transition: transform 0.05s linear;
        }
        .pm3-floor {
          position: absolute;
          left: -300px; top: -200px;
          width: 600px; height: 400px;
          background-image:
            linear-gradient(to right, oklch(0.78 0.12 220 / 0.12) 1px, transparent 1px),
            linear-gradient(to bottom, oklch(0.78 0.12 220 / 0.12) 1px, transparent 1px);
          background-size: 40px 40px;
          transform: rotateX(90deg) translateZ(-160px);
          opacity: 0.6;
        }
        .pm3-edges {
          position: absolute;
          left: -300px; top: -200px;
          width: 600px; height: 400px;
          pointer-events: none;
        }
        .pm3-node {
          position: absolute;
          transform-style: preserve-3d;
          cursor: pointer;
        }
        .pm3-controls {
          position: absolute; top: 12px; left: 12px;
          display: flex; align-items: center; gap: 8px;
          padding: 6px 10px;
          background: oklch(0.10 0.02 240 / 0.6);
          backdrop-filter: blur(12px);
          border: 1px solid rgba(255,240,220,0.08);
          font-size: 12px;
          z-index: 10;
        }
        .pm3-legend {
          position: absolute; top: 12px; right: 12px;
          display: flex; gap: 10px;
          padding: 6px 10px;
          background: oklch(0.10 0.02 240 / 0.6);
          backdrop-filter: blur(12px);
          border: 1px solid rgba(255,240,220,0.08);
          font-family: var(--font-mono);
          font-size: 11px;
          color: var(--text-dim);
        }
        .pm3-detail {
          position: absolute; bottom: 12px; left: 12px; right: 12px;
          background: oklch(0.13 0.02 240 / 0.78);
          backdrop-filter: blur(16px) saturate(140%);
          border: 1px solid rgba(255,240,220,0.10);
          padding: 12px 14px;
          z-index: 10;
        }
        .pm3-empty {
          display: grid; place-items: center;
          background: oklch(0.10 0.02 240 / 0.5);
          border: 1px dashed var(--border-strong);
        }
      `}</style>
    </div>
  );
}

function Stat({ label, v, tone }) {
  return (
    <div style={{
      padding: '4px 8px',
      background: 'rgba(255,240,220,0.04)',
      borderLeft: `2px solid ${tone === 'cyan' ? 'var(--cyan)' : tone === 'signal' ? 'var(--signal)' : tone === 'plant' ? 'var(--plant)' : 'var(--border-strong)'}`,
    }}>
      <div style={{ fontSize: 9, color: 'var(--text-mute)' }}>{label}</div>
      <div style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text)' }}>{v}</div>
    </div>
  );
}

function PersonaNode({ node, selected, onClick }) {
  const ringSize = node.size + 12;
  const color = node.validity >= 70 ? 'oklch(0.74 0.13 145)'  // plant
              : node.validity >= 50 ? 'oklch(0.80 0.15 72)'   // signal
              : 'oklch(0.68 0.21 22)';                         // alert
  return (
    <div
      className="pm3-node"
      style={{
        left: node.x, top: -node.y,
        transform: `translateZ(${node.z}px)`,
      }}
      onClick={(e) => { e.stopPropagation(); onClick(); }}
    >
      {/* Sphere */}
      <div style={{
        position: 'absolute',
        width: node.size,
        height: node.size,
        left: -node.size/2,
        top: -node.size/2,
        borderRadius: '50%',
        background: `radial-gradient(circle at 30% 30%, ${color}, ${color} 30%, oklch(0.20 0.04 240) 80%)`,
        boxShadow: `0 0 ${node.size}px ${color}, inset -4px -6px 14px rgba(0,0,0,0.45)`,
        transform: 'translateZ(0)',
        outline: selected ? `2px solid ${color}` : 'none',
        outlineOffset: 4,
      }} />
      {/* Halo ring */}
      <div style={{
        position: 'absolute',
        width: ringSize,
        height: ringSize,
        left: -ringSize/2,
        top: -ringSize/2,
        border: `1px solid ${color}`,
        borderRadius: '50%',
        opacity: 0.25,
        animation: 'pm3-pulse 3s ease-in-out infinite',
      }} />
      {/* Label */}
      <div style={{
        position: 'absolute',
        left: node.size/2 + 6,
        top: -8,
        fontSize: 11,
        fontWeight: 600,
        color: 'var(--bone-100)',
        textShadow: '0 1px 4px rgba(0,0,0,0.7)',
        whiteSpace: 'nowrap',
      }}>{node.name}</div>
      <style>{`
        @keyframes pm3-pulse {
          0%, 100% { transform: scale(1); opacity: 0.25; }
          50%      { transform: scale(1.4); opacity: 0.08; }
        }
      `}</style>
    </div>
  );
}

function Axis() {
  // 3 lines: X (red), Y (cyan), Z (green)
  return (
    <>
      <div style={{ position: 'absolute', width: 320, height: 1, left: -160, top: 0, background: 'oklch(0.80 0.15 72 / 0.3)' }} />
      <div style={{ position: 'absolute', width: 1, height: 240, left: 0, top: -120, background: 'oklch(0.78 0.12 220 / 0.3)' }} />
      <div style={{ position: 'absolute', width: 1, height: 1, left: 0, top: 0, background: 'oklch(0.74 0.13 145 / 0.3)', transform: 'rotateY(90deg)', boxShadow: '0 0 0 0 oklch(0.74 0.13 145 / 0.3)' }} />
    </>
  );
}

Object.assign(window, { PersonaMap3D });
