/* global React, window */
/* Gráfico isométrico do stack (protótipo /lab). Paleta v1 fiel à referência (periwinkle);
   v2 futura migra para os tokens Moore. Puro SVG, sem libs. */

const ISO_COS = 0.8660254; /* cos 30° */
const ISO_SIN = 0.5;       /* sin 30° */

/* Mundo: +x desce à direita, +y desce à esquerda, +z sobe. */
function iso(x, y, z) {
  return { sx: (x - y) * ISO_COS, sy: (x + y) * ISO_SIN - z };
}
function isoPts(arr) {
  return arr.map((p) => p.sx.toFixed(2) + ',' + p.sy.toFixed(2)).join(' ');
}
/* Plano superior como transformação linear: u (mundo +x) -> (cos, sin), v (mundo +y) -> (-cos, sin). */
function topMatrix(x, y, z) {
  const o = iso(x, y, z);
  return 'matrix(' + ISO_COS + ' ' + ISO_SIN + ' ' + -ISO_COS + ' ' + ISO_SIN + ' ' + o.sx.toFixed(2) + ' ' + o.sy.toFixed(2) + ')';
}
/* Parede frontal-esquerda (plano y = const): horizontal = +x, vertical = -z (desce). */
function leftWallMatrix(x, yFront, zTop) {
  const o = iso(x, yFront, zTop);
  return 'matrix(' + ISO_COS + ' ' + ISO_SIN + ' 0 1 ' + o.sx.toFixed(2) + ' ' + o.sy.toFixed(2) + ')';
}

const BLOCK = { top: '#b6bdfa', left: '#98a1f5', right: '#7f89ef' };
const PLATE = { top: '#ffffff', left: '#e9e6de', right: '#dcd8cc' };
const GRID = '#e7e3d9';
const INK = '#141414';
const EDGE = 'rgba(20,20,20,0.10)';
const DASH = '#7f89ef';
const MONO = '"Geist Mono", ui-monospace, monospace';

function TopFace({ x, y, z, children }) {
  return <g transform={topMatrix(x, y, z)}>{children}</g>;
}

/* Caixa isométrica: 3 faces visíveis + label opcional deitado no topo (string ou array de linhas). */
function Box({ x, y, z, w, d, h, tone, label, labelSize }) {
  const t = tone || BLOCK;
  const A = iso(x, y, z + h), B = iso(x + w, y, z + h), C = iso(x + w, y + d, z + h), D = iso(x, y + d, z + h);
  const E = iso(x + w, y, z), F = iso(x + w, y + d, z), G = iso(x, y + d, z);
  const lines = label ? (Array.isArray(label) ? label : [label]) : null;
  const fs = labelSize || 14;
  return (
    <g>
      <polygon points={isoPts([A, B, C, D])} fill={t.top} stroke={EDGE} strokeWidth="0.75" strokeLinejoin="round" />
      <polygon points={isoPts([D, C, F, G])} fill={t.left} stroke={EDGE} strokeWidth="0.75" strokeLinejoin="round" />
      <polygon points={isoPts([B, E, F, C])} fill={t.right} stroke={EDGE} strokeWidth="0.75" strokeLinejoin="round" />
      {lines ? (
        <TopFace x={x} y={y} z={z + h}>
          <text
            x={w / 2} y={d / 2 - (lines.length - 1) * fs * 0.55}
            textAnchor="middle" dominantBaseline="middle"
            fontFamily={MONO} fontSize={fs} fill={INK} letterSpacing="0.02em"
          >
            {lines.map((ln, i) => (
              <tspan key={i} x={w / 2} dy={i === 0 ? 0 : fs * 1.15}>{ln}</tspan>
            ))}
          </text>
        </TopFace>
      ) : null}
    </g>
  );
}

/* Plataforma 300x300 centrada na origem, espessura 14, com label na borda frontal-esquerda. */
const PW = 300, PT_H = 14;
function Plate({ label, grid, children }) {
  return (
    <g>
      <Box x={-150} y={-150} z={0} w={PW} d={PW} h={PT_H} tone={PLATE} />
      {grid ? (
        <TopFace x={-150} y={-150} z={PT_H}>
          {[30, 60, 90, 120, 150, 180, 210, 240, 270].map((u) => (
            <line key={'u' + u} x1={u} y1={0} x2={u} y2={PW} stroke={GRID} strokeWidth="1" />
          ))}
          {[30, 60, 90, 120, 150, 180, 210, 240, 270].map((v) => (
            <line key={'v' + v} x1={0} y1={v} x2={PW} y2={v} stroke={GRID} strokeWidth="1" />
          ))}
        </TopFace>
      ) : null}
      {label ? (
        <TopFace x={-150} y={-150} z={PT_H}>
          <text x={6} y={326} fontFamily={MONO} fontSize={21} fill={INK} letterSpacing="0.04em">{label}</text>
        </TopFace>
      ) : null}
      <g className="iso-blocks">{children}</g>
    </g>
  );
}

/* 01 · Systems of Record */
function LayerRecord() {
  const z = PT_H;
  return (
    <Plate label="Systems of Record" grid>
      <Box x={-90} y={-125} z={z} w={95} d={55} h={36} label="E-mail" labelSize={13} />
      <Box x={40} y={-70} z={z} w={95} d={55} h={36} label="ERP" labelSize={13} />
      <Box x={-135} y={-15} z={z} w={95} d={55} h={36} label="CRM" labelSize={13} />
      <Box x={-20} y={45} z={z} w={95} d={55} h={36} label="Docs" labelSize={13} />
    </Plate>
  );
}

/* 02 · Data Infrastructure: slab arredondado (Lakehouse) + galpão com telhado (Warehouse) */
function RoundedSlab({ x, y, z, w, d, h, rx, label }) {
  return (
    <g>
      <TopFace x={x} y={y} z={z}>
        <rect x={0} y={0} width={w} height={d} rx={rx} fill={BLOCK.right} />
      </TopFace>
      <TopFace x={x} y={y} z={z + h}>
        <rect x={0} y={0} width={w} height={d} rx={rx} fill={BLOCK.top} stroke={EDGE} strokeWidth="0.75" />
        {label ? (
          <text x={w / 2} y={d / 2} textAnchor="middle" dominantBaseline="middle" fontFamily={MONO} fontSize={14} fill={INK}>{label}</text>
        ) : null}
      </TopFace>
    </g>
  );
}
function Warehouse({ x, y, z, w, d, h, rh, label }) {
  const z1 = z + h;
  const A = iso(x, y, z1), B = iso(x + w, y, z1), C = iso(x + w, y + d, z1), D = iso(x, y + d, z1);
  const P1 = iso(x, y + d / 2, z1 + rh), P2 = iso(x + w, y + d / 2, z1 + rh);
  return (
    <g>
      <Box x={x} y={y} z={z} w={w} d={d} h={h} />
      {/* telhado de duas águas, cumeeira ao longo de x */}
      <polygon points={isoPts([A, B, P2, P1])} fill={BLOCK.top} stroke={EDGE} strokeWidth="0.75" strokeLinejoin="round" />
      <polygon points={isoPts([D, C, P2, P1])} fill={BLOCK.left} stroke={EDGE} strokeWidth="0.75" strokeLinejoin="round" />
      <polygon points={isoPts([B, C, P2])} fill={BLOCK.right} stroke={EDGE} strokeWidth="0.75" strokeLinejoin="round" />
      {label ? (
        <g transform={leftWallMatrix(x, y + d, z1)}>
          <text x={w / 2} y={h / 2} textAnchor="middle" dominantBaseline="middle" fontFamily={MONO} fontSize={13} fill={INK}>{label}</text>
        </g>
      ) : null}
    </g>
  );
}
function LayerData() {
  const z = PT_H;
  return (
    <Plate label="Data Infrastructure">
      {/* conexões pontilhadas sobre a plataforma */}
      <TopFace x={-150} y={-150} z={z}>
        <path d="M 110 190 L 200 190 L 200 130" fill="none" stroke={DASH} strokeWidth="1.5" strokeDasharray="5 5" />
        <path d="M 60 140 L 60 90 L 130 90" fill="none" stroke={DASH} strokeWidth="1.5" strokeDasharray="5 5" />
      </TopFace>
      <Warehouse x={20} y={-95} z={z} w={100} d={72} h={34} rh={22} label="Warehouse" />
      <RoundedSlab x={-125} y={-10} z={z} w={160} d={90} h={12} rx={44} label="Lakehouse" />
    </Plate>
  );
}

/* 03 · Intelligence Layer: colunata com laje "Agents" */
function LayerIntel() {
  const z = PT_H;
  const pillar = { w: 16, d: 16, h: 52 };
  const px = [-58, 34], py = [-34, 12];
  return (
    <Plate label="Intelligence Layer">
      <Box x={-72} y={-48} z={z} w={140} d={92} h={8} />
      {py.map((yy) =>
        px.map((xx) => (
          <Box key={xx + ':' + yy} x={xx} y={yy} z={z + 8} w={pillar.w} d={pillar.d} h={pillar.h} />
        ))
      )}
      <Box x={-80} y={-56} z={z + 8 + pillar.h} w={156} d={108} h={12} label="Agents" labelSize={15} />
    </Plate>
  );
}

/* 04 · Business Modules */
function LayerModules() {
  const z = PT_H;
  return (
    <Plate label="Business Modules" grid>
      <Box x={-55} y={-135} z={z} w={115} d={58} h={40} label={['Customer', 'Service']} labelSize={12.5} />
      <Box x={-145} y={-35} z={z} w={92} d={56} h={40} label="Sales" labelSize={13} />
      <Box x={-15} y={-10} z={z} w={100} d={58} h={40} label="Operations" labelSize={12.5} />
      <Box x={55} y={-75} z={z} w={92} d={56} h={40} label="Procurement" labelSize={11} />
      <Box x={-60} y={70} z={z} w={92} d={56} h={40} label="Finance" labelSize={13} />
    </Plate>
  );
}

const ISO_STEP = 165; /* separação vertical entre camadas (px de viewBox) */
const ISO_GAP = 30;   /* abertura extra ao redor da camada ativa */

function isoLayerOffset(i, active) {
  if (i > active) return -i * ISO_STEP - 2 * ISO_GAP;
  if (i === active) return -i * ISO_STEP - ISO_GAP;
  return -i * ISO_STEP;
}

function IsoStack({ active }) {
  const layers = [<LayerRecord />, <LayerData />, <LayerIntel />, <LayerModules />];
  return (
    <svg className="iso-svg" viewBox="0 0 720 980" aria-hidden="true" focusable="false">
      <defs>
        <filter id="iso-shadow" x="-40%" y="-40%" width="180%" height="180%">
          <feGaussianBlur stdDeviation="14" />
        </filter>
      </defs>
      <g transform="translate(360, 740)">
        <ellipse cx="0" cy="185" rx="290" ry="52" fill="rgba(20,20,20,0.10)" filter="url(#iso-shadow)" />
        {layers.map((L, i) => (
          <g
            key={i}
            className="iso-layer"
            style={{ transform: 'translateY(' + isoLayerOffset(i, active) + 'px)', opacity: i === active ? 1 : 0.35 }}
          >
            {L}
          </g>
        ))}
      </g>
    </svg>
  );
}

window.IsoStack = IsoStack;

/* ---- Variante "zoom" (/lab2): as camadas inativas se fecham num bloco compacto e a
   câmera centraliza a camada ativa, então só o conteúdo dela ocupa a cena. ---- */
const Z_STEP = 64;   /* passo entre plates fechadas */
const Z_GAP = 280;   /* respiro entre a camada ativa e os blocos fechados */
const Z_SCALE = 1.2; /* zoom da câmera na camada ativa */

function zoomOffset(i, active) {
  let y = -i * Z_STEP;
  if (i >= active) y -= Z_GAP;
  if (i > active) y -= Z_GAP;
  return y;
}

function IsoStackZoom({ active }) {
  const layers = [<LayerRecord />, <LayerData />, <LayerIntel />, <LayerModules />];
  /* Foco da câmera: enviesado para deixar o bloco fechado visível (acima da ativa,
     ou abaixo quando a ativa é a do topo). */
  const bias = active === layers.length - 1 ? 80 : -90;
  const centerY = zoomOffset(active, active) - 55 + bias;
  return (
    <svg className="iso-svg" viewBox="0 0 780 780" aria-hidden="true" focusable="false">
      <g transform="translate(390, 390)">
        <g
          className="iso-camera"
          style={{ transform: 'translateY(' + (-Z_SCALE * centerY).toFixed(1) + 'px) scale(' + Z_SCALE + ')' }}
        >
          {layers.map((L, i) => (
            <g
              key={i}
              className={'iso-layer iso-zlayer' + (i === active ? ' is-active' : '')}
              style={{ transform: 'translateY(' + zoomOffset(i, active) + 'px)' }}
            >
              {L}
            </g>
          ))}
        </g>
      </g>
    </svg>
  );
}

window.IsoStackZoom = IsoStackZoom;
