// ============================================================
// VOXEL 3D ENGINE - real isometric Minecraft-style cubes (CSS 3D)
// A <Cube> draws top + 4 sides; backface-culling shows only the
// 3 camera-facing faces. <VoxelIsland> composes the floating
// GigaKöy diorama: grass terrain, tree, branded build, beacon
// uplink + glowing GigaFiber cable reaching off-world.
// ============================================================

const S = 46; // block size in px - keep in sync with --s in index.html

// --- material palette: { top, side (lighter), dark (shaded side), rim? } ---
const MATS = {
  grass:  { top: '#76b23c', side: '#6d4a2a', dark: '#553820', rim: '#5f9531' },
  dirt:   { top: '#7d5635', side: '#6d4a2a', dark: '#523619' },
  stone:  { top: '#83818d', side: '#67656f', dark: '#4c4a52' },
  wood:   { top: '#b58a4e', side: '#71492a', dark: '#5a3a21' },
  leaf:   { top: '#56a23c', side: '#3f7a2c', dark: '#2f5d20' },
  brand:  { top: '#7a37ad', side: '#4f1c73', dark: '#360f50' },   // branded aubergine block
  brandlt:{ top: '#9a55cf', side: '#6a2e9c', dark: '#4f1c73' },
  amber:  { top: '#ffc752', side: '#ed9a23', dark: '#cf8013', emissive: true },
  diamond:{ top: '#9ff0e3', side: '#54c2b4', dark: '#3a988c', emissive: 'cyan' },
  glass:  { top: 'rgba(170,225,255,0.45)', side: 'rgba(120,180,230,0.32)', dark: 'rgba(90,140,200,0.28)' },
};

function faceStyle(color, kind, mat) {
  // kind: 'top' | 'side' | 'dark'
  if (kind === 'top') {
    return {
      background: `linear-gradient(135deg, rgba(255,255,255,0.22), rgba(0,0,0,0) 55%), ${color}`,
    };
  }
  // side faces: shading gradient. grass sides get a thin green rim at the very top.
  const base = `linear-gradient(180deg, rgba(255,255,255,0.10), rgba(0,0,0,0.30)), ${color}`;
  if (mat && mat.rim) {
    return {
      background: `linear-gradient(180deg, ${mat.rim} 0 13%, rgba(0,0,0,0) 13%), linear-gradient(180deg, rgba(255,255,255,0.10), rgba(0,0,0,0.32)), ${color}`,
    };
  }
  return { background: base };
}

function Cube({ gx = 0, gy = 0, gz = 0, mat = 'dirt', delay = 0, build = true, lift = false, className = '', op = 1 }) {
  const m = MATS[mat] || MATS.dirt;
  const pos = { transform: `translate3d(${gx * S}px, ${gy * S}px, ${gz * S}px)`, opacity: op };
  const glow = m.emissive
    ? { boxShadow: m.emissive === 'cyan'
        ? '0 0 16px 2px rgba(120,235,220,0.55)'
        : '0 0 18px 3px rgba(245,166,35,0.6)' }
    : null;

  const Face = (cls, kind, color) => (
    <i className={cx('vox-f', cls)} style={{ ...faceStyle(color, kind, kind === 'side' ? m : null), ...(glow || {}) }} />
  );

  return (
    <div className={cx('vox', lift && 'vox-lift', className)} style={pos}>
      <div
        className={cx(build && 'vox-drop')}
        style={{ position: 'absolute', inset: 0, transformStyle: 'preserve-3d', animationDelay: `${delay}ms` }}
      >
        {Face('vf-top', 'top', m.top)}
        {Face('vf-ri', 'side', m.side)}
        {Face('vf-bk', 'side', m.side)}
        {Face('vf-fr', 'side', m.dark)}
        {Face('vf-le', 'side', m.dark)}
      </div>
    </div>
  );
}

// ---- build the block list for the floating island ----
function islandBlocks() {
  const out = [];
  const push = (gx, gy, gz, mat) => out.push({ gx, gy, gz, mat });

  // grass top surface (organic 5x5, corners trimmed + a couple of nubs)
  const top = [];
  for (let x = -2; x <= 2; x++) for (let y = -2; y <= 2; y++) {
    if (Math.abs(x) === 2 && Math.abs(y) === 2) continue; // trim corners
    top.push([x, y]);
  }
  top.push([3, 0], [-3, 0], [0, 3]); // nubs for organic silhouette
  top.forEach(([x, y]) => push(x, y, 0, 'grass'));

  // dirt body (inset one layer down)
  const dirt = [];
  for (let x = -2; x <= 2; x++) for (let y = -2; y <= 2; y++) {
    if (Math.abs(x) === 2 && Math.abs(y) === 2) continue;
    dirt.push([x, y]);
  }
  dirt.forEach(([x, y]) => push(x, y, -1, 'dirt'));

  // tapering stone underbelly -> floating-island point
  [[-1,-1],[0,-1],[1,-1],[-1,0],[0,0],[1,0],[-1,1],[0,1],[1,1]].forEach(([x,y]) => push(x, y, -2, 'stone'));
  [[0,-1],[0,0],[-1,0],[0,1]].forEach(([x,y]) => push(x, y, -3, 'stone'));
  push(0, 0, -4, 'stone');

  // --- a tree (instantly reads as Minecraft) back-left ---
  const tx = -2, ty = -1;
  push(tx, ty, 1, 'wood'); push(tx, ty, 2, 'wood');
  // canopy 3x3 around top of trunk at z=3, plus a cap at z=4
  for (let x = -1; x <= 1; x++) for (let y = -1; y <= 1; y++) push(tx + x, ty + y, 3, 'leaf');
  push(tx, ty, 4, 'leaf'); push(tx + 1, ty, 4, 'leaf'); push(tx, ty + 1, 4, 'leaf');

  // --- branded build (small house) front-right ---
  const hx = 1, hy = 1;
  // 2x2 footprint walls, 2 high
  const wall = [[0,0],[1,0],[0,1],[1,1]];
  wall.forEach(([x,y]) => { push(hx+x, hy+y, 1, 'brand'); });
  // second layer with a glowing window block
  push(hx, hy, 2, 'brand'); push(hx+1, hy, 2, 'amber'); push(hx, hy+1, 2, 'brand'); push(hx+1, hy+1, 2, 'brandlt');
  // roof cap
  push(hx, hy, 3, 'brandlt');

  // --- beacon uplink (signature focal point) center-back ---
  const bx = 0, by = -2;
  push(bx, by, 1, 'stone');
  push(bx, by, 2, 'brand');
  push(bx, by, 3, 'amber');   // emissive beacon block (beam rises from here)

  return { blocks: out, beacon: { gx: bx, gy: by, gz: 4 } };
}

function VoxelIsland() {
  const { blocks, beacon } = useMemo(islandBlocks, []);

  // sort back-to-front for clean painter ordering: lower z first, then far (low x+y)
  const ordered = useMemo(
    () => blocks
      .map((b, i) => ({ ...b, i }))
      .sort((a, b) => (a.gz - b.gz) || ((a.gx + a.gy) - (b.gx + b.gy))),
    [blocks]
  );

  return (
    <div className="vox-stage relative w-full h-full select-none">
      <div className="absolute left-1/2 top-1/2 vox-world" style={{ transform: 'translate(-50%,-50%) rotateX(56deg) rotateZ(-46deg)' }}>
        <div className="vox-bob" style={{ position: 'absolute', transformStyle: 'preserve-3d' }}>
          {/* base + structures */}
          {ordered.map((b) => {
            const dist = (b.gz + 4); // build bottom-up
            return (
              <Cube key={b.i} gx={b.gx} gy={b.gy} gz={b.gz} mat={b.mat} delay={300 + dist * 90} />
            );
          })}

          {/* GigaFiber cable - glowing amber line from beacon base across grass + off the front edge */}
          <FiberCable />

          {/* beacon light beam - single camera-facing (billboard) vertical shaft */}
          <div
            className="beam"
            style={{
              position: 'absolute',
              transformOrigin: 'bottom center',
              transform: `translate3d(${beacon.gx * S + S*0.5}px, ${beacon.gy * S + S*0.5}px, ${beacon.gz * S}px) rotateZ(46deg) rotateX(-56deg)`,
              width: S * 0.62, height: 300,
              marginLeft: -S * 0.31,
              background: 'linear-gradient(to top, rgba(255,205,90,0.9), rgba(255,215,130,0.22) 50%, rgba(255,215,130,0))',
              filter: 'blur(2px)',
              pointerEvents: 'none',
            }}
          />

          {/* floating ore cubes bobbing above */}
          <Cube gx={2.4} gy={-0.4} gz={3.2} mat="amber" lift build={false} className="ore-glow" />
          <Cube gx={-1.2} gy={2.2} gz={3.6} mat="diamond" lift build={false} className="ore-glow" />
          <Cube gx={0.6} gy={1.6} gz={4.4} mat="amber" lift build={false} className="ore-glow" />
        </div>
      </div>
    </div>
  );
}

// glowing fiber cable: a run of small amber cubes from beacon base, across the
// surface, then dropping off the front edge toward the world below.
function FiberCable() {
  const seg = [];
  // along surface (z just above grass top)
  const path = [
    [0, -1.5, 0.55], [0, -1, 0.55], [0.4, -0.5, 0.55], [0.8, 0, 0.55],
    [1.1, 0.4, 0.55], [1.4, 0.9, 0.55],
    // drop off front edge toward viewer/world
    [1.8, 1.6, 0.3], [2.1, 2.2, -0.4], [2.3, 2.7, -1.4], [2.45, 3.1, -2.6], [2.55, 3.4, -3.9],
  ];
  return (
    <>
      {path.map(([x, y, z], i) => (
        <div
          key={i}
          className="ore-glow"
          style={{
            position: 'absolute',
            transform: `translate3d(${x * S}px, ${y * S}px, ${z * S}px)`,
            width: S * 0.3, height: S * 0.3, borderRadius: 3,
            background: 'linear-gradient(135deg,#ffe6a8,#f5a623)',
            boxShadow: '0 0 12px 2px rgba(245,166,35,0.7)',
            animationDelay: `${i * 140}ms`,
          }}
        />
      ))}
    </>
  );
}

Object.assign(window, { Cube, VoxelIsland, FiberCable, MATS, VOX_S: S });

/* ---- legacy poster helpers used by the Episode video frame ---- */
function PosterBlocks() {
  const cols = useMemo(() => [3,5,4,6,8,5,7,9,11,8,9,12,10,9,11,13,10,8,9,7,5,6,4,3,2,3,5,4,3,2], []);
  return (
    <svg viewBox="0 0 300 200" className="absolute inset-x-0 bottom-0 w-full h-2/3" preserveAspectRatio="none">
      <defs>
        <linearGradient id="blockg" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0%" stopColor="#3d1659" stopOpacity="0.9"/>
          <stop offset="100%" stopColor="#0e0712" stopOpacity="1"/>
        </linearGradient>
      </defs>
      {cols.map((h, i) => (
        <rect key={i} x={i*10} y={200 - h*12} width="9" height={h*12} fill="url(#blockg)"
              stroke="rgba(245,166,35,0.18)" strokeWidth="0.5" />
      ))}
      {[[40,40],[110,28],[200,52],[260,32]].map(([x,y],i)=>(
        <rect key={i} x={x} y={y} width="14" height="14" fill="rgba(245,166,35,0.18)" stroke="rgba(245,166,35,0.5)"/>
      ))}
    </svg>
  );
}

function FiberStrands() {
  return (
    <svg viewBox="0 0 300 400" className="absolute inset-0 w-full h-full" preserveAspectRatio="none">
      <defs>
        <linearGradient id="strand" x1="0" x2="1" y1="0" y2="0">
          <stop offset="0%" stopColor="rgba(245,166,35,0)"/>
          <stop offset="50%" stopColor="rgba(255,210,120,0.85)"/>
          <stop offset="100%" stopColor="rgba(245,166,35,0)"/>
        </linearGradient>
      </defs>
      {[80,160,240,320].map((y,i)=>(
        <path key={i} d={`M -10 ${y} Q 80 ${y - 30 - i*4} 150 ${y + i*6} T 320 ${y - 10}`}
              fill="none" stroke="url(#strand)" strokeWidth="1"
              strokeDasharray="6 240" className="fiber-line"
              style={{animationDelay: `${i*1.4}s`}}/>
      ))}
    </svg>
  );
}

Object.assign(window, { PosterBlocks, FiberStrands });
