/* App.jsx — Main Application */
const { useState, useEffect, useRef, useCallback } = React;

function Viewport({ engineRef, onEngineReady, onDragFile }) {
  const canvasRef = useRef(null);
  const [ready, setReady] = useState(false);
  const [dragging, setDragging] = useState(false);

  useEffect(() => {
    const init = () => {
      if (!window.ThreeEngine || !canvasRef.current) return;
      engineRef.current = new window.ThreeEngine(canvasRef.current);
      setReady(true);
      onEngineReady(engineRef.current);
    };
    if (window.ThreeEngine) init();else
    window.addEventListener('engineReady', init, { once: true });
    return () => engineRef.current?.dispose();
  }, []);

  const handleDrop = useCallback((e) => {
    e.preventDefault();setDragging(false);
    const f = e.dataTransfer.files[0];
    if (f) onDragFile(f);
  }, [onDragFile]);

  return (
    <div style={{ flex: 1, position: 'relative', overflow: 'hidden', background: '#080810' }}
    onDragOver={(e) => {e.preventDefault();setDragging(true);}}
    onDragLeave={() => setDragging(false)}
    onDrop={handleDrop}>
<canvas ref={canvasRef} style={{ width: '100%', display: 'block', height: '100%', padding: 0, opacity: 1 }} />
      {!ready &&
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 12, pointerEvents: 'none' }}>
          <div style={{ width: 28, height: 28, border: '2px solid var(--border)', borderTopColor: 'var(--accent)', borderRadius: '50%', animation: 'spin 1s linear infinite' }} />
          <span style={{ fontSize: 11, color: 'var(--t3)' }}>Загрузка движка…</span>
        </div>
      }

      {dragging &&
      <div style={{ position: 'absolute', inset: 8, background: 'rgba(94,92,230,.1)', border: '2px dashed var(--accent)', borderRadius: 12, display: 'flex', alignItems: 'center', justifyContent: 'center', pointerEvents: 'none' }}>
          <span style={{ fontSize: 14, color: 'var(--accent)', fontWeight: 500 }}>Перетащите SVG или GLB</span>
        </div>
      }

      {/* Camera presets */}
      {ready &&
      <div style={{ position: 'absolute', bottom: 14, left: '50%', transform: 'translateX(-50%)', display: 'flex', gap: 3, background: 'rgba(15,15,20,.85)', backdropFilter: 'blur(10px)', borderRadius: 8, padding: '3px 5px', border: '1px solid var(--border)' }}>
          {[['Перспектива', 'perspective'], ['Спереди', 'front'], ['Сверху', 'top'], ['Сбоку', 'side']].map(([l, k]) =>
        <button key={k} onClick={() => engineRef.current?.resetCamera(k)} style={{
          padding: '3px 9px', fontSize: 10, background: 'none', border: 'none', cursor: 'pointer',
          color: 'var(--t2)', borderRadius: 5, fontFamily: 'inherit'
        }}
        onMouseEnter={(e) => e.currentTarget.style.color = 'var(--t1)'}
        onMouseLeave={(e) => e.currentTarget.style.color = 'var(--t2)'}>
              {l}
            </button>
        )}
        </div>
      }

      {/* Hint when empty */}
      {ready &&
      <div id="viewport-hint" style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', textAlign: 'center', pointerEvents: 'none', transition: 'opacity .3s' }}>
          <div style={{ fontSize: 13, color: 'var(--t3)', lineHeight: 2 }}>
            Перетащите SVG-иконку<br />или добавьте объект из панели слева
          </div>
        </div>
      }
    </div>);

}

function App() {
  const [objects, setObjects] = useState([]);
  const [selectedId, setSelectedId] = useState(null);
  const [transformMode, setTransformMode] = useState('translate');
  const engineRef = useRef(null);
  const svgInputRef = useRef(null);
  const gltfInputRef = useRef(null);

  // Hide viewport hint when there are objects
  useEffect(() => {
    const hint = document.getElementById('viewport-hint');
    if (hint) hint.style.opacity = objects.length > 0 ? '0' : '1';
  }, [objects]);

  // Sync transform mode to engine (only when engine is ready)
  useEffect(() => {
    if (engineRef.current?.setTransformMode) {
      engineRef.current.setTransformMode(transformMode);
    }
  }, [transformMode]);

  // Sync selection to engine (attach/detach gizmo)
  useEffect(() => {
    if (engineRef.current?.selectObject) {
      engineRef.current.selectObject(selectedId);
    }
  }, [selectedId]);

  // Keyboard shortcuts
  useEffect(() => {
    const handler = (e) => {
      const tag = document.activeElement?.tagName;
      if (tag === 'INPUT' || tag === 'TEXTAREA') return;
      switch (e.key) {
        case 'Delete':
        case 'Backspace':
          if (selectedId) handleDelete(selectedId);
          break;
        case 't':case 'T':setTransformMode('translate');break;
        case 'r':case 'R':setTransformMode('rotate');break;
        case 's':case 'S':setTransformMode('scale');break;
        case 'Escape':setSelectedId(null);break;
        case 'd':case 'D':
          if ((e.ctrlKey || e.metaKey) && selectedId) {e.preventDefault();handleDuplicate(selectedId);}
          break;
        case 'f':case 'F':
          engineRef.current?.resetCamera('perspective');break;
      }
    };
    window.addEventListener('keydown', handler);
    return () => window.removeEventListener('keydown', handler);
  }, [selectedId]);

  const handleEngineReady = useCallback((engine) => {
    engine.onSelect = (id) => setSelectedId(id);
    engine.onObjectsChange = (list) => setObjects(list);
  }, []);

  const handleSVGFile = useCallback(async (file) => {
    if (!file || !engineRef.current) return;
    const text = await file.text();
    const id = engineRef.current.addSVG(text, { name: file.name.replace(/\.svg$/i, '') });
    if (id) setSelectedId(id);
  }, []);

  const handleGLTFFile = useCallback(async (file) => {
    if (!file || !engineRef.current) return;
    const url = URL.createObjectURL(file);
    try {
      const id = await engineRef.current.loadGLTF(url, file.name.replace(/\.[^.]+$/, ''));
      if (id) setSelectedId(id);
    } finally {URL.revokeObjectURL(url);}
  }, []);

  const handleDragFile = useCallback((file) => {
    const name = file.name.toLowerCase();
    if (name.endsWith('.svg') || file.type === 'image/svg+xml') handleSVGFile(file);else
    if (name.endsWith('.glb') || name.endsWith('.gltf')) handleGLTFFile(file);
  }, [handleSVGFile, handleGLTFFile]);

  const handleAddPrimitive = useCallback((type) => {
    if (!engineRef.current) return;
    const id = engineRef.current.addPrimitive(type);
    if (id) setSelectedId(id);
  }, []);

  const handleDelete = useCallback((id) => {
    engineRef.current?.removeObject(id);
    if (selectedId === id) setSelectedId(null);
  }, [selectedId]);

  const handleDuplicate = useCallback((id) => {
    const newId = engineRef.current?.duplicateObject(id);
    if (newId) setSelectedId(newId);
  }, []);

  const handleToggleVisible = useCallback((id, visible) => {
    engineRef.current?.setObjectVisible(id, visible);
    setObjects((prev) => prev.map((o) => o.id === id ? { ...o, visible } : o));
  }, []);

  const handleRename = useCallback((id, name) => {
    engineRef.current?.setObjectName(id, name);
  }, []);

  const selectedType = selectedId ? engineRef.current?.getObjectType(selectedId) : null;

  return (
    <div style={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column', background: 'var(--bg0)', overflow: 'hidden' }}>
      <style>{`
        @keyframes spin { to { transform: rotate(360deg); } }
        *, *::before, *::after { box-sizing: border-box; }
        ::-webkit-scrollbar { width: 4px; height: 4px; }
        ::-webkit-scrollbar-track { background: transparent; }
        ::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
      `}</style>

      <Toolbar
        transformMode={transformMode}
        setTransformMode={(mode) => {setTransformMode(mode);engineRef.current?.setTransformMode(mode);}}
        onReset={() => engineRef.current?.resetCamera('perspective')}
        onAddSVG={() => svgInputRef.current?.click()} />
      

      <div style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
        <LeftPanel
          objects={objects}
          selectedId={selectedId}
          onSelect={setSelectedId}
          onAddSVG={() => svgInputRef.current?.click()}
          onAddGLTF={() => gltfInputRef.current?.click()}
          onAddPrimitive={handleAddPrimitive}
          onDelete={handleDelete}
          onDuplicate={handleDuplicate}
          onToggleVisible={handleToggleVisible}
          onRename={handleRename} />
        
        <Viewport
          engineRef={engineRef}
          onEngineReady={handleEngineReady}
          onDragFile={handleDragFile} />
        
        <RightPanel
          selectedId={selectedId}
          objectType={selectedType}
          engineRef={engineRef} />
        
      </div>

      {/* Keyboard hint */}
      <div style={{ position: 'fixed', bottom: 52, left: '50%', transform: 'translateX(-50%)',
        background: 'rgba(15,15,20,.75)', backdropFilter: 'blur(8px)', border: '1px solid var(--border)',
        borderRadius: 7, padding: '4px 12px', fontSize: 10, color: 'var(--t3)',
        display: 'flex', gap: 12, pointerEvents: 'none', zIndex: 50 }}>
        <span><kbd style={kbdSt}>T</kbd> Переместить</span>
        <span><kbd style={kbdSt}>R</kbd> Повернуть</span>
        <span><kbd style={kbdSt}>S</kbd> Масштаб</span>
        <span><kbd style={kbdSt}>Del</kbd> Удалить</span>
        <span><kbd style={kbdSt}>Ctrl+D</kbd> Копия</span>
        <span><kbd style={kbdSt}>F</kbd> Сбросить камеру</span>
      </div>

      <input ref={svgInputRef} type="file" accept=".svg,image/svg+xml" style={{ display: 'none' }}
      onChange={(e) => {if (e.target.files[0]) handleSVGFile(e.target.files[0]);e.target.value = '';}} />
      <input ref={gltfInputRef} type="file" accept=".glb,.gltf" style={{ display: 'none' }}
      onChange={(e) => {if (e.target.files[0]) handleGLTFFile(e.target.files[0]);e.target.value = '';}} />
    </div>);

}

const kbdSt = {
  background: 'var(--bg3)', border: '1px solid var(--border)', borderRadius: 3,
  padding: '1px 4px', fontSize: 9, color: 'var(--t2)', fontFamily: 'inherit'
};

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
