// Preview-режим модели — мини-редактор. Фаза 5.6 RUBLOX_DESIGNER_PLAN.md.
//
// URL: https://player.rublox.pro/_preview-model/<itemId>#team_jwt=<JWT>
//
// Что умеет:
//   1. Пустой мир, модель в центре, гизмо привязано — двигай, крути, масштабируй.
//   2. Кнопки тулбара: Select / Move / Rotate / Scale (хоткеи Q/W/E/R),
//      Reset (вернуть модель в (0,0,0)), Play (запустить персонажа).
//   3. Play: спавнится персонаж рядом с моделью, WASD/Space — можно
//      бегать, прыгать, проверять коллизии. Кнопка Stop → назад в editor.
//
// Используется ВСЯ инфра editor'a плеера: ModelManager.addInstance + 'url:<URL>'
// (см. ModelManager._resolveModelType, мы добавили туда case),
// SelectionManager, GizmoController, BabylonScene.enterPlayMode/exitPlayMode.
//
// Когда rublox-site editor будет готов как полноценный игровой редактор
// (RUBLOX_EDITOR_ROADMAP.md) — этот test-режим перенести туда.

import { useEffect, useRef, useState } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useAuth } from '../auth/PlayerAuth';
import { BabylonScene } from '../engine/BabylonScene';
import * as Kubikon3DApi from '../api/Kubikon3DService';
import LoadingScreen from '../LoadingScreen';

export default function PreviewModelRoute() {
  const { itemId } = useParams();
  const navigate = useNavigate();
  const { isAuthenticated, isLoading: authLoading, error: authError } = useAuth();

  const canvasRef = useRef(null);
  const sceneRef = useRef(null);
  const modelInstanceIdRef = useRef(null);
  const [model, setModel] = useState(null);
  const [loadErr, setLoadErr] = useState(null);
  const [phase, setPhase] = useState('auth');     // auth | loading | ready | error
  const [gizmoMode, setGizmoMode] = useState('move');
  const [isPlaying, setIsPlaying] = useState(false);

  // 1) грузим item
  useEffect(() => {
    if (!isAuthenticated) return;
    setPhase('loading');
    Kubikon3DApi.getDesignerModel(itemId)
      .then((r) => {
        const m = r?.data?.item || r?.data || r;
        if (!m || !m.file_path) throw new Error('Модель не найдена');
        setModel(m);
      })
      .catch((e) => {
        const msg = e?.response?.data?.message
                 || e?.response?.data?.error
                 || e?.message || 'Не удалось загрузить модель';
        setLoadErr(msg);
        setPhase('error');
      });
  }, [isAuthenticated, itemId]);

  // 2) инит сцены + спавн модели + выделение + гизмо
  useEffect(() => {
    if (!model || !canvasRef.current) return;
    if (sceneRef.current) return;

    let scene;
    let destroyed = false;
    (async () => {
      try {
        scene = new BabylonScene(canvasRef.current);
        sceneRef.current = scene;
        scene.init();
        // По умолчанию у BabylonScene activeTool='block' (ставит grass-кубы
        // при клике). Для preview-режима это не нужно — переключаем на
        // 'select' чтобы курсор просто выделял модель и работал с гизмо.
        try { scene.setActiveTool?.('select'); } catch (e) {}
        // Спавним модель в (0, 0.5, 0) через ModelManager — он умеет
        // 'url:<URL>' с момента подфазы 5.6 (см. _resolveModelType).
        // y=0.5 чтобы модель стояла НА земле (если её origin в центре, то 0.5)
        const instanceId = await scene.modelManager?.addInstance?.(
          'url:' + model.file_path, 0, 0.5, 0, 0,
        );
        if (destroyed) return;
        if (instanceId == null) {
          throw new Error('ModelManager не смог загрузить модель');
        }
        modelInstanceIdRef.current = instanceId;
        // Выделяем модель — это автоматом привяжет гизмо через
        // _updateGizmoForSelection (BabylonScene:1311).
        try {
          scene.selection?.selectModelByInstanceId?.(instanceId);
        } catch (e) { /* selection mог не уметь — гизмо подключим вручную */ }
        // Дефолтный режим — move
        scene.setGizmoMode?.('move');
        setGizmoMode('move');
        setPhase('ready');
      } catch (e) {
        // eslint-disable-next-line no-console
        console.error('[PreviewModel] scene init failed', e);
        if (!destroyed) {
          setLoadErr(e?.message || 'Ошибка инициализации сцены');
          setPhase('error');
        }
      }
    })();

    return () => {
      destroyed = true;
      try {
        if (scene && typeof scene.dispose === 'function') scene.dispose();
        else if (scene && scene.engine) scene.engine.dispose();
      } catch (e) { /* ignore */ }
      sceneRef.current = null;
    };
  }, [model]);

  // 3) хоткеи Q/W/E/R + Space
  useEffect(() => {
    function onKey(e) {
      // не перехватываем если в инпуте
      if (e.target && (e.target.tagName === 'INPUT'
                   || e.target.tagName === 'TEXTAREA')) return;
      if (isPlaying) return;  // в Play режиме плеер сам управляет клавишами
      const k = e.key.toLowerCase();
      if (k === 'q') changeMode('select');
      else if (k === 'w') changeMode('move');
      else if (k === 'e') changeMode('rotate');
      else if (k === 'r') changeMode('scale');
    }
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [isPlaying]);

  function changeMode(m) {
    setGizmoMode(m);
    const scene = sceneRef.current;
    if (!scene) return;
    scene.setGizmoMode?.(m);
    // Любое из 4 положений тулбара = курсор «select», а не «class blocks/models».
    // Без этого клик на сцену ставит grass-кубы (BabylonScene._activeTool='block' по умолчанию).
    try { scene.setActiveTool?.('select'); } catch (e) {}
  }

  function resetModel() {
    const scene = sceneRef.current;
    const iid = modelInstanceIdRef.current;
    if (!scene || iid == null) return;
    const inst = scene.modelManager?.getInstance?.(iid)
              || scene.modelManager?._instances?.get?.(iid);
    if (!inst || !inst.root) return;
    inst.root.position.x = 0;
    inst.root.position.y = 0.5;
    inst.root.position.z = 0;
    inst.root.rotation.y = 0;
    inst.root.scaling.set(1, 1, 1);
  }

  function togglePlay() {
    const scene = sceneRef.current;
    if (!scene) return;
    if (!isPlaying) {
      // Спавним персонажа в (3, 1, 0) — рядом, чтобы видеть модель в кадре
      try { scene.spawnPoint = { x: 3, y: 1, z: 0 }; } catch (e) {}
      try { scene.setPlayerModelType?.('skin_bacon-hair'); } catch (e) {}
      try { scene.enterPlayMode?.(); } catch (e) {
        // eslint-disable-next-line no-console
        console.warn('enterPlayMode failed', e);
      }
      setIsPlaying(true);
    } else {
      try { scene.exitPlayMode?.(); } catch (e) {}
      setIsPlaying(false);
      // После exit гизмо могло слетать — переподключаем
      const iid = modelInstanceIdRef.current;
      if (iid != null) {
        try { scene.selection?.selectModelByInstanceId?.(iid); } catch (e) {}
        try { scene.setGizmoMode?.(gizmoMode); } catch (e) {}
      }
    }
  }

  // ─── render ────────────────────────────────────────────────────────

  if (authLoading) return <LoadingScreen text="Подключение" />;
  if (authError === 'no_jwt_local') {
    return <LoadingScreen text="Нужен JWT"
                          subText="Открой из team.rublox.pro кнопкой «Тестировать»."/>;
  }
  if (!isAuthenticated) {
    return <LoadingScreen text="Сессия истекла"
                          subText="Вернись в team.rublox.pro и попробуй снова."/>;
  }

  return (
    <div style={{ position: 'fixed', inset: 0, background: '#000' }}>
      <canvas ref={canvasRef}
              style={{ width: '100%', height: '100%', display: 'block',
                       touchAction: 'none', outline: 'none' }}/>

      {/* Верхний баннер */}
      <div style={bannerStyle}>
        <div style={{ fontWeight: 700, fontSize: 14 }}>
          Тест модели: «{model ? model.name : '...'}»
        </div>
        <div style={{ fontSize: 12, opacity: 0.7, marginTop: 2 }}>
          {model ? `${model.category} · ${model.target_height || 1.0} м` : ''}
          {model && model.status !== 'published' && (
            <span style={{ color: '#ffcc66', marginLeft: 8 }}>
              · {model.status === 'draft' ? 'черновик' : 'на проверке'}
            </span>
          )}
        </div>
        <button onClick={() => { try { window.close(); } catch (e) {} navigate('/'); }}
                style={closeBtnStyle}>Закрыть</button>
      </div>

      {/* Тулбар */}
      {phase === 'ready' && (
        <div style={toolbarStyle}>
          {!isPlaying && (
            <>
              <ToolBtn active={gizmoMode === 'select'} onClick={() => changeMode('select')}
                       label="Курсор" hint="Q"/>
              <ToolBtn active={gizmoMode === 'move'} onClick={() => changeMode('move')}
                       label="Move" hint="W"/>
              <ToolBtn active={gizmoMode === 'rotate'} onClick={() => changeMode('rotate')}
                       label="Rotate" hint="E"/>
              <ToolBtn active={gizmoMode === 'scale'} onClick={() => changeMode('scale')}
                       label="Scale" hint="R"/>
              <div style={separator}/>
              <ToolBtn onClick={resetModel} label="Reset"
                       hint="модель в (0, 0)"/>
              <div style={separator}/>
            </>
          )}
          <ToolBtn onClick={togglePlay}
                   primary={!isPlaying}
                   danger={isPlaying}
                   label={isPlaying ? '⏹ Стоп' : '▶ Запустить'}
                   hint={isPlaying ? 'выйти из игры' : 'побегать персонажем'}/>
        </div>
      )}

      {phase === 'loading' && (
        <div style={overlayStyle}><div>Загрузка модели…</div></div>
      )}
      {phase === 'error' && (
        <div style={overlayStyle}>
          <div style={{ color: '#ff8888', fontWeight: 700, marginBottom: 8 }}>
            Не удалось загрузить модель
          </div>
          <div style={{ fontSize: 13, opacity: 0.85, maxWidth: 420, textAlign: 'center' }}>
            {loadErr}
          </div>
          <button onClick={() => window.close()}
                  style={{ ...closeBtnStyle, marginTop: 12, position: 'static' }}>
            Закрыть
          </button>
        </div>
      )}
    </div>
  );
}

function ToolBtn({ active, primary, danger, onClick, label, hint }) {
  const bg = active ? '#3357ff'
           : primary ? '#1e9a51'
           : danger ? '#a93232'
           : 'rgba(255,255,255,0.08)';
  const color = (active || primary || danger) ? '#fff' : '#cfd6e6';
  return (
    <button onClick={onClick} title={hint}
            style={{
              padding: '7px 12px', fontSize: 13, fontWeight: 600,
              background: bg, color, border: '1px solid rgba(255,255,255,0.12)',
              borderRadius: 6, cursor: 'pointer',
              display: 'inline-flex', alignItems: 'center', gap: 6,
            }}>
      {label}
      {hint && hint.length <= 3 && (
        <span style={{
          fontSize: 10, padding: '1px 5px', borderRadius: 3,
          background: 'rgba(0,0,0,0.3)', opacity: 0.7,
        }}>{hint}</span>
      )}
    </button>
  );
}

const bannerStyle = {
  position: 'absolute', top: 12, left: 12,
  background: 'rgba(10, 14, 26, 0.88)', color: '#f1f5fb',
  // padding-right больше, чтобы текст никогда не залезал под кнопку «Закрыть»
  // (она absolute в правом верхнем углу баннера, ширина ~70px).
  padding: '10px 90px 10px 14px',
  borderRadius: 8, border: '1px solid rgba(255,255,255,0.10)',
  fontFamily: '"Roboto Condensed", system-ui, sans-serif',
  maxWidth: 'calc(100vw - 40px)',
  // Делаем баннер inline-block чтобы кнопка позиционировалась относительно него.
  display: 'inline-block',
};
const closeBtnStyle = {
  position: 'absolute', top: 10, right: 10,
  background: 'rgba(255, 111, 122, 0.18)', color: '#ff6f7a',
  border: '1px solid rgba(255, 111, 122, 0.40)',
  borderRadius: 6, padding: '4px 10px',
  fontSize: 12, fontWeight: 700, cursor: 'pointer',
};
const overlayStyle = {
  position: 'absolute', inset: 0,
  background: 'rgba(0,0,0,0.65)', color: '#fff',
  display: 'flex', alignItems: 'center', justifyContent: 'center',
  flexDirection: 'column', fontFamily: 'system-ui, sans-serif',
};
const toolbarStyle = {
  position: 'absolute', bottom: 16, left: '50%', transform: 'translateX(-50%)',
  background: 'rgba(10, 14, 26, 0.92)',
  border: '1px solid rgba(255,255,255,0.10)',
  borderRadius: 10, padding: 8, gap: 6,
  display: 'inline-flex', alignItems: 'center',
  fontFamily: '"Roboto Condensed", system-ui, sans-serif',
};
const separator = {
  width: 1, height: 22, background: 'rgba(255,255,255,0.15)',
  margin: '0 2px',
};
