/**
 * GdBossesPreview — превью-страница для просмотра всех 10 GD-боссов разом.
 *
 * Маршрут: /admin-preview/gd-bosses
 *
 * Для каждого босса делает мини-Babylon-сцену с вращающейся моделью.
 * МИН открывает страницу, смотрит все 10 в виде сетки, по каждому даёт фидбэк.
 * Доступ — только для админа.
 *
 * Источник данных: kubikon3d_user_models (id 164-173, см. RUBLOX_GD_BOSSES_REGISTRY.md).
 */
import React, { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../auth/AuthContext.jsx';
import { getUserModel } from '../api/Kubikon3DService';
import { decodeVoxelModel } from '../editor/engine/voxelModelCodec';
import styles from './GdBossesPreview.module.css';

import { Engine } from '@babylonjs/core/Engines/engine';
import { Scene } from '@babylonjs/core/scene';
import { ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera';
import { HemisphericLight } from '@babylonjs/core/Lights/hemisphericLight';
import { DirectionalLight } from '@babylonjs/core/Lights/directionalLight';
import { Vector3, Color3, Color4 } from '@babylonjs/core/Maths/math';
import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder';
import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
import { VertexData } from '@babylonjs/core/Meshes/mesh.vertexData';
import { Mesh } from '@babylonjs/core/Meshes/mesh';

// ID из реестра RUBLOX_GD_BOSSES_REGISTRY.md
const BOSSES = [
  { level: 10, title: 'Стражник леса', modelId: 164, description: 'Деревянный голем с горящими жёлтыми глазами. Корона из веток.' },
  { level: 20, title: 'Король горы', modelId: 165, description: 'Йети с ледяной короной. Снежно-белый мех.' },
  { level: 30, title: 'Хозяин города', modelId: 166, description: 'Робот-небоскрёб с окнами-глазами и красным маяком.' },
  { level: 40, title: 'Призрак ночи', modelId: 167, description: 'Полупрозрачный фиолетовый фантом с magenta-глазами.' },
  { level: 50, title: 'Король пустыни', modelId: 168, description: 'Сфинкс с золотой маской фараона.' },
  { level: 60, title: 'Левиафан', modelId: 169, description: 'Морской змей с большими белыми зубами.' },
  { level: 70, title: 'Хранитель глубин', modelId: 170, description: 'Каменный голем-минотавр с лавовыми жилами и кристальными рогами.' },
  { level: 80, title: 'Дракон вулкана', modelId: 171, description: 'Огнедышащий дракон с шипастой спиной и крыльями.' },
  { level: 90, title: 'Космический владыка', modelId: 172, description: 'НЛО-корабль с куполом, неоновыми окнами и тремя двигателями.' },
  { level: 100, title: 'АРХИТЕКТОР', modelId: 173, description: 'Финальный босс. Неоновая спираль + пирамида со всевидящим глазом.' },
];

const VOXEL_SIZE = 0.0625;  // совпадает с UserModelManager — 1/16 м

/**
 * Построить меш одной воксельной модели в сцене.
 * Один меш = один воксель (для простоты). При size=64 это до 262144 кубов,
 * но реально вокселей ~10000 — Babylon справляется.
 */
function buildVoxelMesh(scene, decoded, name) {
  if (!decoded || !decoded.voxels) return null;

  // Группируем воксели по цвету для оптимизации (один меш на цвет)
  const byColor = new Map();
  for (const v of decoded.voxels) {
    const c = v.c || '#ffffff';
    if (!byColor.has(c)) byColor.set(c, []);
    byColor.get(c).push(v);
  }

  const parent = new Mesh(name + '_root', scene);
  const halfSize = decoded.size / 2;

  let colorIdx = 0;
  for (const [hex, voxels] of byColor.entries()) {
    // Собираем геометрию вручную (vertex buffer) — без instances для простоты
    const positions = [];
    const normals = [];
    const indices = [];
    let vIdx = 0;

    for (const v of voxels) {
      // Центр воксели в мире
      const wx = (v.x - halfSize) * VOXEL_SIZE;
      const wy = (v.y) * VOXEL_SIZE;
      const wz = (v.z - halfSize) * VOXEL_SIZE;
      const s = VOXEL_SIZE / 2;

      // 8 углов куба
      const corners = [
        [wx - s, wy - s, wz - s], [wx + s, wy - s, wz - s],
        [wx + s, wy + s, wz - s], [wx - s, wy + s, wz - s],
        [wx - s, wy - s, wz + s], [wx + s, wy - s, wz + s],
        [wx + s, wy + s, wz + s], [wx - s, wy + s, wz + s],
      ];
      // 6 граней (12 треугольников)
      const faces = [
        [0, 1, 2, 3, 0, 0, -1],  // back
        [5, 4, 7, 6, 0, 0, 1],   // front
        [4, 0, 3, 7, -1, 0, 0],  // left
        [1, 5, 6, 2, 1, 0, 0],   // right
        [3, 2, 6, 7, 0, 1, 0],   // top
        [4, 5, 1, 0, 0, -1, 0],  // bottom
      ];
      for (const [a, b, c, d, nx, ny, nz] of faces) {
        for (const i of [a, b, c, d]) {
          positions.push(corners[i][0], corners[i][1], corners[i][2]);
          normals.push(nx, ny, nz);
        }
        indices.push(vIdx, vIdx + 1, vIdx + 2, vIdx, vIdx + 2, vIdx + 3);
        vIdx += 4;
      }
    }

    const mesh = new Mesh(`${name}_${colorIdx}`, scene);
    const vd = new VertexData();
    vd.positions = positions;
    vd.normals = normals;
    vd.indices = indices;
    vd.applyToMesh(mesh);

    const mat = new StandardMaterial(`mat_${name}_${colorIdx}`, scene);
    const col = Color3.FromHexString(hex);
    mat.diffuseColor = col;
    mat.specularColor = new Color3(0.1, 0.1, 0.1);
    // Светящиеся (emissive) цвета — определим эвристически: ярко-насыщенные
    const max = Math.max(col.r, col.g, col.b);
    const min = Math.min(col.r, col.g, col.b);
    const sat = max > 0 ? (max - min) / max : 0;
    if (sat > 0.7 && max > 0.7) {
      mat.emissiveColor = col.scale(0.5);
    }
    mesh.material = mat;
    mesh.parent = parent;
    colorIdx++;
  }

  return parent;
}


function BossPreviewCard({ boss }) {
  const canvasRef = useRef(null);
  const [status, setStatus] = useState('loading');
  const [stats, setStats] = useState(null);

  useEffect(() => {
    let cancelled = false;
    let engine = null;

    async function init() {
      try {
        const resp = await getUserModel(boss.modelId);
        if (cancelled) return;
        const modelData = resp.data?.model_data;
        const decoded = decodeVoxelModel(modelData);
        if (!decoded) throw new Error('decode failed');

        if (!canvasRef.current) return;
        engine = new Engine(canvasRef.current, true, { preserveDrawingBuffer: true });
        const scene = new Scene(engine);
        scene.clearColor = new Color4(0.12, 0.14, 0.20, 1);

        // Камера — арк, медленно вращается вокруг
        const camera = new ArcRotateCamera('cam',
          -Math.PI / 2 - 0.3, Math.PI / 2.4,
          decoded.size * VOXEL_SIZE * 2.2,
          new Vector3(0, decoded.size * VOXEL_SIZE / 2, 0),
          scene);
        camera.attachControl(canvasRef.current, true);
        camera.wheelPrecision = 50;
        camera.lowerRadiusLimit = decoded.size * VOXEL_SIZE * 1.2;
        camera.upperRadiusLimit = decoded.size * VOXEL_SIZE * 4;

        // Освещение
        const hemi = new HemisphericLight('hemi', new Vector3(0, 1, 0), scene);
        hemi.intensity = 0.7;
        hemi.groundColor = new Color3(0.3, 0.3, 0.4);
        const dir = new DirectionalLight('dir', new Vector3(-0.5, -1, -0.3), scene);
        dir.intensity = 0.6;

        // Платформа под боссом
        const ground = MeshBuilder.CreateDisc('ground',
          { radius: decoded.size * VOXEL_SIZE * 0.7, tessellation: 32 }, scene);
        ground.rotation.x = Math.PI / 2;
        const groundMat = new StandardMaterial('groundMat', scene);
        groundMat.diffuseColor = new Color3(0.2, 0.22, 0.28);
        ground.material = groundMat;

        // Меш модели
        const mesh = buildVoxelMesh(scene, decoded, `boss_${boss.modelId}`);

        // Автовращение
        scene.onBeforeRenderObservable.add(() => {
          camera.alpha += 0.003;
        });

        engine.runRenderLoop(() => scene.render());
        const onResize = () => engine.resize();
        window.addEventListener('resize', onResize);

        setStats({
          voxels: decoded.voxels.length,
          size: decoded.size,
          colors: new Set(decoded.voxels.map(v => v.c)).size,
        });
        setStatus('ok');

        // cleanup
        return () => {
          window.removeEventListener('resize', onResize);
        };
      } catch (e) {
        console.error(`[BossPreview L${boss.level}]`, e);
        setStatus('error: ' + e.message);
      }
    }
    init();

    return () => {
      cancelled = true;
      if (engine) {
        try { engine.dispose(); } catch (_) {}
      }
    };
  }, [boss.modelId]);

  return (
    <div className={styles.card}>
      <div className={styles.header}>
        <span className={styles.levelBadge}>L{boss.level}</span>
        <h3 className={styles.title}>{boss.title}</h3>
      </div>
      <div className={styles.canvasWrap}>
        <canvas ref={canvasRef} className={styles.canvas} />
        {status !== 'ok' && (
          <div className={styles.overlay}>{status}</div>
        )}
      </div>
      <div className={styles.description}>{boss.description}</div>
      {stats && (
        <div className={styles.stats}>
          📦 {stats.size}³ · 🎨 {stats.colors} цв. · 🧱 {stats.voxels} вокс.
          · <a href={`/edit/models/${boss.modelId}`} target="_blank" rel="noopener noreferrer">открыть в редакторе</a>
        </div>
      )}
    </div>
  );
}


function GdBossesPreview() {
  const { userRole, isLoading } = useAuth();
  const navigate = useNavigate();

  if (isLoading) return <div className={styles.loading}>Загрузка...</div>;
  if (userRole !== 'admin') {
    return (
      <div className={styles.denied}>
        <h2>Доступ только для администратора</h2>
        <button onClick={() => navigate('/')} className={styles.backBtn}>На главную</button>
      </div>
    );
  }

  return (
    <div className={styles.root}>
      <div className={styles.topbar}>
        <h1 className={styles.h1}>GD-Боссы — превью 10 моделей</h1>
        <div className={styles.subline}>
          Источник: <code>kubikon3d_user_models</code> id 164-173 · реестр в <code>RUBLOX_GD_BOSSES_REGISTRY.md</code>
        </div>
      </div>

      <div className={styles.grid}>
        {BOSSES.map(b => <BossPreviewCard key={b.modelId} boss={b} />)}
      </div>

      <div className={styles.footer}>
        <p>Жми/тащи мышью на любой превью — можно покрутить модель руками.</p>
        <p>Если нужны правки — скажи МИНу какие, я подкручу Python-генератор и перезалью.</p>
      </div>
    </div>
  );
}

export default GdBossesPreview;
