import React, { Suspense, useRef, useEffect } from 'react';
import { Canvas, useThree } from '@react-three/fiber';
import {
  OrbitControls, Grid, GizmoHelper,
  GizmoViewport, Sky, Stars, TransformControls,
} from '@react-three/drei';
import * as THREE from 'three';
import { useStudioStore } from '../store/useStudioStore';
import { Model, ModelHandle } from './Model';
import './Viewport.css';

// ── One model + its optional TransformControls ────────────────
const ModelWithGizmo: React.FC<{
  obj: any;
  isSelected: boolean;
  gizmoMode: 'translate' | 'rotate' | 'scale';
  onOrbitEnable: (v: boolean) => void;
}> = ({ obj, isSelected, gizmoMode, onOrbitEnable }) => {
  const modelRef = useRef<ModelHandle>(null);
  const { updateObject, setSelectedId } = useStudioStore();

  const syncTransform = () => {
    const g = modelRef.current?.group;
    if (!g) return;
    updateObject(obj.id, {
      position: [+g.position.x.toFixed(3), +g.position.y.toFixed(3), +g.position.z.toFixed(3)],
      rotation: [
        +THREE.MathUtils.radToDeg(g.rotation.x).toFixed(2),
        +THREE.MathUtils.radToDeg(g.rotation.y).toFixed(2),
        +THREE.MathUtils.radToDeg(g.rotation.z).toFixed(2),
      ],
      scale: [+g.scale.x.toFixed(3), +g.scale.y.toFixed(3), +g.scale.z.toFixed(3)],
    });
  };

  return (
    <>
      <Model
        ref={modelRef}
        obj={obj}
        isSelected={isSelected}
        onClick={() => setSelectedId(obj.id)}
      />
      {isSelected && modelRef.current?.group && (
        <TransformControls
          object={modelRef.current.group}
          mode={gizmoMode}
          size={0.9}
          onMouseDown={() => onOrbitEnable(false)}
          onMouseUp={() => { onOrbitEnable(true); syncTransform(); }}
          onChange={syncTransform}
        />
      )}
    </>
  );
};

// ── HDR / equirectangular skybox ──────────────────────────────
const SkyboxHDR: React.FC<{ url: string }> = ({ url }) => {
  const { scene } = useThree();
  useEffect(() => {
    new THREE.TextureLoader().load(url, (tex) => {
      tex.mapping = THREE.EquirectangularReflectionMapping;
      scene.background = tex;
      scene.environment = tex;
    });
  }, [url, scene]);
  return null;
};

// ── Main scene content ────────────────────────────────────────
const SceneContent: React.FC = () => {
  const {
    objects, selectedId,
    ambientIntensity, directionalIntensity,
    showGrid, showAxes,
    skyboxType, skyboxUrl, bgColor,
    mode, gizmoMode,
  } = useStudioStore();

  const { scene } = useThree();
  const orbitRef  = useRef<any>(null);

  useEffect(() => {
    if (skyboxType !== 'uploaded')
      scene.background = new THREE.Color(bgColor);
  }, [bgColor, skyboxType, scene]);

  const setOrbit = (v: boolean) => {
    if (orbitRef.current) orbitRef.current.enabled = v;
  };

  return (
    <>
      <ambientLight intensity={ambientIntensity} />
      <directionalLight
        position={[5, 10, 5]}
        intensity={directionalIntensity}
        castShadow
        shadow-mapSize={[2048, 2048]}
      />
      <directionalLight position={[-5, 5, -5]} intensity={directionalIntensity * 0.3} />

      {skyboxType === 'gradient' && (
        <Sky sunPosition={[100, 20, 100]} turbidity={8} rayleigh={2} />
      )}
      {skyboxType === 'uploaded' && skyboxUrl && <SkyboxHDR url={skyboxUrl} />}
      {mode === 'render' && (
        <Stars radius={100} depth={50} count={3000} factor={4} />
      )}

      <Suspense fallback={null}>
        {objects.map((obj) => (
          <ModelWithGizmo
            key={obj.id}
            obj={obj}
            isSelected={selectedId === obj.id}
            gizmoMode={gizmoMode}
            onOrbitEnable={setOrbit}
          />
        ))}
      </Suspense>

      {showGrid && (
        <Grid
          position={[0, -0.01, 0]}
          args={[20, 20]}
          cellSize={1}
          cellThickness={0.5}
          cellColor="#444466"
          sectionSize={5}
          sectionThickness={1}
          sectionColor="#6666aa"
          fadeDistance={30}
          infiniteGrid
        />
      )}
      {showAxes && <axesHelper args={[5]} />}

      <OrbitControls ref={orbitRef} makeDefault />
      <GizmoHelper alignment="bottom-right" margin={[80, 80]}>
        <GizmoViewport
          axisColors={['#f06292', '#66bb6a', '#42a5f5']}
          labelColor="white"
        />
      </GizmoHelper>
    </>
  );
};

// ── Viewport root ─────────────────────────────────────────────
const Viewport: React.FC = () => {
  const { gizmoMode, setGizmoMode, mode } = useStudioStore();

  return (
    <div className="viewport">

      {/* Floating gizmo mode toolbar — only in MODEL mode */}
      {mode === 'model' && (
        <div className="gizmo-toolbar">
          {([
            { id: 'translate', icon: '✛', label: 'Move',   key: 'G' },
            { id: 'rotate',    icon: '↻', label: 'Rotate', key: 'R' },
            { id: 'scale',     icon: '⤢', label: 'Scale',  key: 'S' },
          ] as const).map((g) => (
            <button
              key={g.id}
              className={`gizmo-btn ${gizmoMode === g.id ? 'active' : ''}`}
              onClick={() => setGizmoMode(g.id)}
              title={`${g.label} (${g.key})`}
            >
              <span className="gizmo-icon">{g.icon}</span>
              <span>{g.label}</span>
              <span className="gizmo-key">{g.key}</span>
            </button>
          ))}
        </div>
      )}

      <Canvas
        shadows
        camera={{ position: [5, 5, 5], fov: 50 }}
        gl={{
          antialias: true,
          toneMapping: THREE.ACESFilmicToneMapping,
          toneMappingExposure: 1,
          preserveDrawingBuffer: true,   // required for video recording
        }}
        onPointerMissed={() => useStudioStore.getState().setSelectedId(null)}
      >
        <SceneContent />
      </Canvas>
    </div>
  );
};

export default Viewport;