import { useRef, useMemo, useEffect, useState } from 'react';
import { Canvas, useFrame, useThree, ThreeEvent } from '@react-three/fiber';
import * as THREE from 'three';
import { mainCameraRef, mainControlsRef, requestView } from './three/viewCubeBus';

/** Builds a square canvas texture with a label centered on it. */
function makeFaceTexture(label: string, accent: boolean): THREE.CanvasTexture {
  const size = 256;
  const c = document.createElement('canvas');
  c.width = size;
  c.height = size;
  const ctx = c.getContext('2d')!;
  // Background
  const grad = ctx.createLinearGradient(0, 0, 0, size);
  grad.addColorStop(0, accent ? '#1a2742' : '#101725');
  grad.addColorStop(1, accent ? '#0c1424' : '#070b14');
  ctx.fillStyle = grad;
  ctx.fillRect(0, 0, size, size);
  // Border
  ctx.strokeStyle = '#00f3ff';
  ctx.lineWidth = 6;
  ctx.strokeRect(3, 3, size - 6, size - 6);
  // Label
  ctx.fillStyle = '#e6faff';
  ctx.font = '700 56px JetBrains Mono, ui-monospace, monospace';
  ctx.textAlign = 'center';
  ctx.textBaseline = 'middle';
  ctx.shadowColor = '#00f3ff';
  ctx.shadowBlur = 18;
  ctx.fillText(label, size / 2, size / 2);
  const tex = new THREE.CanvasTexture(c);
  tex.anisotropy = 4;
  tex.needsUpdate = true;
  return tex;
}

const FACE_DEFS: { label: string; dir: [number, number, number] }[] = [
  // BoxGeometry material order: +X, -X, +Y, -Y, +Z, -Z
  { label: 'DIR',    dir: [ 1, 0, 0] },
  { label: 'ESQ',    dir: [-1, 0, 0] },
  { label: 'TOPO',   dir: [ 0, 1, 0] },
  { label: 'BASE',   dir: [ 0,-1, 0] },
  { label: 'FRENTE', dir: [ 0, 0, 1] },
  { label: 'ATRÁS',  dir: [ 0, 0,-1] },
];

function CubeMesh() {
  const meshRef = useRef<THREE.Mesh>(null);
  const { camera: localCam } = useThree();
  const [hover, setHover] = useState<number | null>(null);

  const materials = useMemo(() => {
    return FACE_DEFS.map((f, i) => {
      const tex = makeFaceTexture(f.label, false);
      const mat = new THREE.MeshBasicMaterial({ map: tex });
      mat.userData.baseTex = tex;
      mat.userData.hoverTex = makeFaceTexture(f.label, true);
      mat.userData.faceIndex = i;
      return mat;
    });
  }, []);

  useEffect(() => {
    return () => {
      materials.forEach((m) => {
        m.userData.baseTex?.dispose?.();
        m.userData.hoverTex?.dispose?.();
        m.dispose();
      });
    };
  }, [materials]);

  // Apply hover tint
  useEffect(() => {
    materials.forEach((m, i) => {
      m.map = i === hover ? m.userData.hoverTex : m.userData.baseTex;
      m.needsUpdate = true;
    });
  }, [hover, materials]);

  // Mirror main camera orientation each frame
  useFrame(() => {
    const main = mainCameraRef.current;
    const controls = mainControlsRef.current;
    if (!main) return;
    const target: THREE.Vector3 = controls?.target ?? new THREE.Vector3();
    const dir = new THREE.Vector3().subVectors(main.position, target).normalize();
    // Place local cam along same direction at fixed distance
    localCam.position.copy(dir.multiplyScalar(3));
    localCam.up.copy(main.up);
    localCam.lookAt(0, 0, 0);
  });

  const onClick = (e: ThreeEvent<MouseEvent>) => {
    e.stopPropagation();
    const idx = e.face?.materialIndex;
    if (idx == null) return;
    const def = FACE_DEFS[idx];
    if (!def) return;
    requestView(new THREE.Vector3(...def.dir));
  };

  return (
    <mesh
      ref={meshRef}
      material={materials}
      onClick={onClick}
      onPointerMove={(e) => {
        e.stopPropagation();
        const idx = e.face?.materialIndex ?? null;
        setHover(idx);
      }}
      onPointerOut={() => setHover(null)}
    >
      <boxGeometry args={[1.4, 1.4, 1.4]} />
    </mesh>
  );
}

/** Tiny axis tripod next to the cube to reinforce the UCS reading. */
function AxisTripod() {
  return (
    <group position={[-1.2, -1.2, 0]}>
      <arrowHelper args={[new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 0, 0), 0.7, 0xff4444, 0.18, 0.12]} />
      <arrowHelper args={[new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, 0, 0), 0.7, 0x44ff66, 0.18, 0.12]} />
      <arrowHelper args={[new THREE.Vector3(0, 0, 1), new THREE.Vector3(0, 0, 0), 0.7, 0x4488ff, 0.18, 0.12]} />
    </group>
  );
}

export function ViewCube() {
  return (
    <div
      className="absolute right-3 top-3 z-20 h-[120px] w-[120px] rounded-md border border-primary/30 bg-background/40 backdrop-blur-sm shadow-lg"
      style={{ pointerEvents: 'auto' }}
      title="Cubo de vistas — clique numa face para girar"
    >
      <Canvas
        camera={{ position: [2, 2, 2], fov: 35, near: 0.1, far: 50 }}
        gl={{ antialias: true, alpha: true }}
        dpr={[1, 2]}
      >
        <ambientLight intensity={1} />
        <CubeMesh />
        <AxisTripod />
      </Canvas>
    </div>
  );
}
