import { useEffect, useRef, useState } from "react";
import { Link } from "react-router-dom";
import { Canvas, useFrame } from "@react-three/fiber";
import {
  OrbitControls,
  Grid,
  Environment,
  PerspectiveCamera,
} from "@react-three/drei";
import * as THREE from "three";
import {
  Beaker,
  ArrowLeft,
  Lock,
  Unlock,
  RotateCcw,
  Hand,
} from "lucide-react";

/**
 * ============================================================
 * QUEST CUBE LAB — Fase 3 e 4
 * - Cubo 3D real + Mesa de dois níveis
 * - Sistema de alinhamento por clique duplo:
 *   1. Seleciona face do cubo
 *   2. Seleciona superfície da mesa (tampo ou prateleira) -> cubo deita na superfície
 *   3. Seleciona outra face do cubo (ortogonal à primeira)
 *   4. Seleciona aresta (lateral/frente) da mesa -> cubo rotaciona e alinha face
 * ============================================================
 */

const STICK_DEADZONE = 0.12;
const TRIGGER_DEADZONE = 0.05;
const MOVE_SPEED = 1.5;
const ROT_SPEED = 1.2;
const SCALE_SPEED = 0.6;
const CUBE_SIZE = 1;

type AlignPhase = 'IDLE' | 'WAIT_SURFACE' | 'WAIT_FACE2' | 'WAIT_EDGE';

// ===================================================================
// COMPONENTE: CuboControlado
// ===================================================================
const CubeControlado = ({
  posRef,
  rotRef,
  scaleRef,
  lockedRef,
  gamepadRef,
  alignPhase,
  setAlignPhase,
  face1Ref,
  face2Ref,
}: {
  posRef: React.MutableRefObject<{ x: number; y: number; z: number }>;
  rotRef: React.MutableRefObject<{ x: number; y: number; z: number }>;
  scaleRef: React.MutableRefObject<number>;
  lockedRef: React.MutableRefObject<boolean>;
  gamepadRef: React.MutableRefObject<{ a: boolean }>;
  alignPhase: AlignPhase;
  setAlignPhase: (p: AlignPhase) => void;
  face1Ref: React.MutableRefObject<THREE.Vector3>;
  face2Ref: React.MutableRefObject<THREE.Vector3>;
}) => {
  const meshRef = useRef<THREE.Mesh>(null);

  const materials = [
    new THREE.MeshStandardMaterial({ color: "#ef4444" }), // +x
    new THREE.MeshStandardMaterial({ color: "#22c55e" }), // -x
    new THREE.MeshStandardMaterial({ color: "#3b82f6" }), // +y
    new THREE.MeshStandardMaterial({ color: "#facc15" }), // -y
    new THREE.MeshStandardMaterial({ color: "#a855f7" }), // +z
    new THREE.MeshStandardMaterial({ color: "#06b6d4" }), // -z
  ];

  useFrame((state, delta) => {
    if (!meshRef.current) return;

    const gamepads = navigator.getGamepads ? navigator.getGamepads() : [];
    const gp = gamepads[0];

    if (gp && !lockedRef.current && alignPhase === 'IDLE') {
      const lx = gp.axes[0] ?? 0;
      const ly = gp.axes[1] ?? 0;
      const rx = gp.axes[2] ?? 0;
      const ry = gp.axes[3] ?? 0;
      const lt = gp.buttons[6]?.value ?? 0;
      const rt = gp.buttons[7]?.value ?? 0;
      const aBtn = gp.buttons[0]?.pressed;

      const ax = Math.abs(lx) > STICK_DEADZONE ? lx : 0;
      const ay = Math.abs(ly) > STICK_DEADZONE ? ly : 0;
      const arx = Math.abs(rx) > STICK_DEADZONE ? rx : 0;
      const ary = Math.abs(ry) > STICK_DEADZONE ? ry : 0;

      posRef.current.x -= ax * MOVE_SPEED * delta;
      posRef.current.z -= ay * MOVE_SPEED * delta;
      posRef.current.y = Math.max(0.5, posRef.current.y);

      rotRef.current.x = (rotRef.current.x + ary * ROT_SPEED * delta) % (Math.PI * 2);
      rotRef.current.y = (rotRef.current.y - arx * ROT_SPEED * delta) % (Math.PI * 2);

      const scaleDelta = rt - lt;
      if (Math.abs(scaleDelta) > TRIGGER_DEADZONE) {
        scaleRef.current = Math.max(0.2, Math.min(3, scaleRef.current + scaleDelta * SCALE_SPEED * delta));
      }

      if (aBtn && !gamepadRef.current.a) {
        posRef.current = { x: 0, y: 0.5, z: 0 };
        rotRef.current = { x: 0, y: 0, z: 0 };
        scaleRef.current = 1;
      }
      gamepadRef.current.a = aBtn;
    } else if (gp && lockedRef.current) {
      const rx = gp.axes[2] ?? 0;
      const ry = gp.axes[3] ?? 0;
      const arx = Math.abs(rx) > STICK_DEADZONE ? rx : 0;
      const ary = Math.abs(ry) > STICK_DEADZONE ? ry : 0;
      rotRef.current.x = (rotRef.current.x + ary * ROT_SPEED * delta) % (Math.PI * 2);
      rotRef.current.y = (rotRef.current.y - arx * ROT_SPEED * delta) % (Math.PI * 2);
    }

    meshRef.current.position.set(posRef.current.x, posRef.current.y, posRef.current.z);
    meshRef.current.rotation.set(rotRef.current.x, rotRef.current.y, rotRef.current.z);
    meshRef.current.scale.setScalar(scaleRef.current);
  });

  return (
    <mesh
      ref={meshRef}
      castShadow
      receiveShadow
      position={[0, 0.5, 0]}
      onClick={(e) => {
        e.stopPropagation();
        if (!e.intersections[0].face) return;
        const localNormal = e.intersections[0].face.normal;

        if (alignPhase === 'IDLE') {
          face1Ref.current.copy(localNormal);
          setAlignPhase('WAIT_SURFACE');
        } else if (alignPhase === 'WAIT_FACE2') {
          if (Math.abs(face1Ref.current.dot(localNormal)) < 0.1) {
            face2Ref.current.copy(localNormal);
            setAlignPhase('WAIT_EDGE');
          } else {
            alert("Por favor, selecione uma face diferente da primeira (ortogonal) para alinhar a direção.");
          }
        }
      }}
      onPointerOver={(e) => { e.stopPropagation(); document.body.style.cursor = 'pointer'; }}
      onPointerOut={() => { document.body.style.cursor = 'auto'; }}
    >
      <boxGeometry args={[CUBE_SIZE, CUBE_SIZE, CUBE_SIZE]} />
      {materials.map((m, i) => (
        <primitive attach={`material-${i}`} object={m} key={i} />
      ))}
    </mesh>
  );
};

// ===================================================================
// COMPONENTE: Mesa (Table)
// ===================================================================
const Table = ({
  onSurfaceClick,
  onEdgeClick,
}: {
  onSurfaceClick: (p: THREE.Vector3, n: THREE.Vector3) => void;
  onEdgeClick: (p: THREE.Vector3, n: THREE.Vector3) => void;
}) => {
  const handleClick = (e: any) => {
    e.stopPropagation();
    if (!e.intersections[0].face) return;
    const n = e.intersections[0].face.normal;
    // Identifica se clicou no topo (Y forte) ou nas laterais (X ou Z fortes)
    if (Math.abs(n.y) > 0.9) {
      onSurfaceClick(e.point, n);
    } else {
      onEdgeClick(e.point, n);
    }
  };

  return (
    <group position={[0, 0, -2]}>
      {/* Tampo Superior */}
      <mesh position={[0, 1, 0]} onClick={handleClick} castShadow receiveShadow>
        <boxGeometry args={[2, 0.1, 1]} />
        <meshStandardMaterial color="#8B4513" />
      </mesh>
      {/* Prateleira Inferior */}
      <mesh position={[0, 0.5, 0]} onClick={handleClick} castShadow receiveShadow>
        <boxGeometry args={[2, 0.1, 1]} />
        <meshStandardMaterial color="#A0522D" />
      </mesh>
      {/* Pés */}
      <mesh position={[-0.9, 0.5, 0.4]} castShadow receiveShadow><boxGeometry args={[0.1, 1, 0.1]} /><meshStandardMaterial color="#5c3a21" /></mesh>
      <mesh position={[0.9, 0.5, 0.4]} castShadow receiveShadow><boxGeometry args={[0.1, 1, 0.1]} /><meshStandardMaterial color="#5c3a21" /></mesh>
      <mesh position={[-0.9, 0.5, -0.4]} castShadow receiveShadow><boxGeometry args={[0.1, 1, 0.1]} /><meshStandardMaterial color="#5c3a21" /></mesh>
      <mesh position={[0.9, 0.5, -0.4]} castShadow receiveShadow><boxGeometry args={[0.1, 1, 0.1]} /><meshStandardMaterial color="#5c3a21" /></mesh>
    </group>
  );
};

const useGamepadStatus = () => {
  const [connected, setConnected] = useState(false);
  useEffect(() => {
    const handler = () => {
      const pads = navigator.getGamepads?.() ?? [];
      setConnected(Array.from(pads).some((p) => p !== null));
    };
    window.addEventListener("gamepadconnected", handler);
    window.addEventListener("gamepaddisconnected", handler);
    handler();
    const i = window.setInterval(handler, 1000);
    return () => {
      window.removeEventListener("gamepadconnected", handler);
      window.removeEventListener("gamepaddisconnected", handler);
      window.clearInterval(i);
    };
  }, []);
  return connected;
};

// ===================================================================
// Página principal
// ===================================================================
const QuestCubeLab = () => {
  const joystickConnected = useGamepadStatus();

  const [cubePos, setCubePos] = useState({ x: 0, y: 0.5, z: 0 });
  const [cubeRot, setCubeRot] = useState({ x: 0, y: 0, z: 0 });
  const [cubeScale, setCubeScale] = useState(1);
  const [locked, setLocked] = useState(false);
  const [alignPhase, setAlignPhase] = useState<AlignPhase>('IDLE');
  
  const face1Ref = useRef(new THREE.Vector3());
  const face2Ref = useRef(new THREE.Vector3());
  const surfaceNormalRef = useRef(new THREE.Vector3());

  const [xrSupported] = useState(() =>
    typeof navigator !== "undefined" &&
    "xr" in navigator &&
    typeof (navigator as any).xr?.isSessionSupported === "function"
  );

  const posRef = useRef(cubePos);
  const rotRef = useRef(cubeRot);
  const scaleRef = useRef(cubeScale);
  const lockedRef = useRef(locked);
  const gamepadRef = useRef({ a: false });

  useEffect(() => { posRef.current = cubePos; }, [cubePos]);
  useEffect(() => { rotRef.current = cubeRot; }, [cubeRot]);
  useEffect(() => { scaleRef.current = cubeScale; }, [cubeScale]);
  useEffect(() => { lockedRef.current = locked; }, [locked]);

  useEffect(() => {
    const id = window.setInterval(() => {
      setCubePos({ ...posRef.current });
      setCubeRot({ ...rotRef.current });
      setCubeScale(scaleRef.current);
    }, 100);
    return () => window.clearInterval(id);
  }, []);

  const reset = () => {
    posRef.current = { x: 0, y: 0.5, z: 0 };
    rotRef.current = { x: 0, y: 0, z: 0 };
    scaleRef.current = 1;
    setCubePos({ x: 0, y: 0.5, z: 0 });
    setCubeRot({ x: 0, y: 0, z: 0 });
    setCubeScale(1);
    setAlignPhase('IDLE');
  };

  const enterXR = async () => {
    try {
      const xr = (navigator as any).xr;
      const session = await xr.requestSession("immersive-ar");
      void session;
      alert("XR session requisitada.");
    } catch (e) {
      alert("Falha ao entrar em XR: " + (e as Error).message);
    }
  };

  const handleSurfaceClick = (point: THREE.Vector3, normal: THREE.Vector3) => {
    if (alignPhase === 'WAIT_SURFACE') {
      surfaceNormalRef.current.copy(normal);
      
      const t1 = normal.clone().negate();
      const q1 = new THREE.Quaternion().setFromUnitVectors(face1Ref.current, t1);
      
      const euler = new THREE.Euler().setFromQuaternion(q1, 'XYZ');
      setCubeRot({ x: euler.x, y: euler.y, z: euler.z });
      rotRef.current = { x: euler.x, y: euler.y, z: euler.z };

      const halfSize = (CUBE_SIZE / 2) * scaleRef.current;
      const newPos = point.clone().add(normal.clone().multiplyScalar(halfSize));
      setCubePos({ x: newPos.x, y: newPos.y, z: newPos.z });
      posRef.current = { x: newPos.x, y: newPos.y, z: newPos.z };

      setAlignPhase('WAIT_FACE2');
    }
  };

  const handleEdgeClick = (point: THREE.Vector3, edgeNormal: THREE.Vector3) => {
    if (alignPhase === 'WAIT_EDGE') {
      const t1 = surfaceNormalRef.current.clone().negate();
      const q1 = new THREE.Quaternion().setFromUnitVectors(face1Ref.current, t1);
      
      const w2 = face2Ref.current.clone().applyQuaternion(q1);
      const t2 = edgeNormal.clone();

      w2.projectOnPlane(surfaceNormalRef.current).normalize();
      t2.projectOnPlane(surfaceNormalRef.current).normalize();

      const angle = Math.atan2(
        w2.clone().cross(t2).dot(surfaceNormalRef.current),
        w2.dot(t2)
      );

      const q2 = new THREE.Quaternion().setFromAxisAngle(surfaceNormalRef.current, angle);
      const finalQ = q2.multiply(q1);
      
      const euler = new THREE.Euler().setFromQuaternion(finalQ, 'XYZ');
      setCubeRot({ x: euler.x, y: euler.y, z: euler.z });
      rotRef.current = { x: euler.x, y: euler.y, z: euler.z };

      setAlignPhase('IDLE');
    }
  };

  return (
    <div className="min-h-screen bg-gradient-to-b from-slate-950 via-slate-900 to-slate-950 text-slate-100">
      <header className="border-b border-slate-800/80 bg-slate-950/80 backdrop-blur">
        <div className="mx-auto flex max-w-6xl items-center justify-between gap-3 px-6 py-4">
          <Link to="/" className="flex items-center gap-2 text-sm text-slate-400 transition hover:text-slate-100">
            <ArrowLeft className="h-4 w-4" /> Voltar ao SteelXR
          </Link>
          <div className="flex items-center gap-3">
            <Beaker className="h-5 w-5 text-amber-400" />
            <h1 className="font-mono text-sm tracking-wider text-slate-300">
              QUEST CUBE LAB <span className="text-amber-400/70">(alpha)</span>
            </h1>
          </div>
          <div className="flex items-center gap-3">
            <span className={`inline-flex h-2 w-2 rounded-full ${joystickConnected ? "bg-emerald-400" : "bg-slate-600"}`} />
            <span className="text-xs text-slate-400">{joystickConnected ? "Joystick OK" : "Sem joystick"}</span>
          </div>
        </div>
      </header>

      <main className="mx-auto max-w-6xl px-6 py-8 relative">
        <div className="mb-6 flex gap-4">
          <div className="flex-1 rounded-lg border border-amber-500/30 bg-amber-500/5 px-4 py-3 text-sm text-amber-200">
            <strong>Fase 3/4 — Sistema de Alinhamento:</strong>
            <ul className="mt-2 list-disc pl-5">
              <li>1. Clique numa face do cubo; depois, numa superfície da mesa (Tampo ou Prateleira).</li>
              <li>2. Clique noutra face ortogonal do cubo; depois, numa borda/lateral da mesa.</li>
            </ul>
          </div>
        </div>

        <div className="mb-4 flex flex-wrap items-center gap-2">
          <button
            onClick={() => setLocked((v) => !v)}
            className={`flex items-center gap-2 rounded-md border px-3 py-2 text-sm font-medium transition ${
              locked ? "border-amber-500 bg-amber-500/15 text-amber-200" : "border-slate-700 bg-slate-900 text-slate-300 hover:border-slate-500"
            }`}
          >
            {locked ? <Lock className="h-4 w-4" /> : <Unlock className="h-4 w-4" />}
            {locked ? "Travado" : "Destravar"}
          </button>

          <button onClick={reset} className="flex items-center gap-2 rounded-md border border-slate-700 bg-slate-900 px-3 py-2 text-sm text-slate-300 transition hover:border-slate-500">
            <RotateCcw className="h-4 w-4" />
            Reset
          </button>
          
          {alignPhase !== 'IDLE' && (
            <button onClick={() => setAlignPhase('IDLE')} className="flex items-center gap-2 rounded-md border border-red-500/50 bg-red-900/30 px-3 py-2 text-sm text-red-300 transition hover:border-red-500">
              Cancelar Alinhamento
            </button>
          )}

          <div className="ml-auto flex items-center gap-2">
            <button
              disabled={!xrSupported}
              onClick={enterXR}
              className={`flex items-center gap-2 rounded-md border px-3 py-2 text-sm transition ${
                xrSupported ? "border-emerald-500/50 bg-emerald-500/10 text-emerald-200 hover:bg-emerald-500/20" : "cursor-not-allowed border-slate-700 bg-slate-900 text-slate-500"
              }`}
            >
              <Hand className="h-4 w-4" />
              Entrar em AR
            </button>
          </div>
        </div>

        <section className="relative overflow-hidden rounded-xl border border-slate-800 bg-slate-950">
          <div className="absolute top-4 left-4 z-10 rounded bg-slate-900/90 p-4 text-sm border border-slate-700/50 backdrop-blur pointer-events-none max-w-sm">
            <div className="font-bold text-amber-300 mb-1 flex items-center gap-2">
              Status Alinhamento
            </div>
            <div className="text-slate-300">
              {alignPhase === 'IDLE' && 'Livre! Clique em uma face do cubo para iniciar o contato.'}
              {alignPhase === 'WAIT_SURFACE' && 'Face gravada! Agora clique em uma superfície da mesa (Tampo/Prateleira) para apoiar o cubo.'}
              {alignPhase === 'WAIT_FACE2' && 'Apoiado! Agora clique em outra face do cubo para alinhamento lateral.'}
              {alignPhase === 'WAIT_EDGE' && 'Último passo! Clique em uma borda ou lateral da mesa para alinhar o cubo.'}
            </div>
          </div>

          <div style={{ height: 600 }}>
            <Canvas shadows>
              <PerspectiveCamera makeDefault position={[3, 4, 6]} fov={50} />
              <ambientLight intensity={0.5} />
              <directionalLight position={[5, 8, 5]} intensity={1} castShadow shadow-mapSize-width={1024} shadow-mapSize-height={1024} />
              
              <CubeControlado
                posRef={posRef}
                rotRef={rotRef}
                scaleRef={scaleRef}
                lockedRef={lockedRef}
                gamepadRef={gamepadRef}
                alignPhase={alignPhase}
                setAlignPhase={setAlignPhase}
                face1Ref={face1Ref}
                face2Ref={face2Ref}
              />
              
              <Table 
                onSurfaceClick={handleSurfaceClick}
                onEdgeClick={handleEdgeClick}
              />

              <Grid args={[20, 20]} cellSize={0.25} cellThickness={0.5} cellColor="#475569" sectionSize={1} sectionThickness={1} sectionColor="#94a3b8" fadeDistance={18} fadeStrength={1} infiniteGrid={false} position={[0, 0, 0]} />
              <mesh receiveShadow rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.001, 0]}>
                <planeGeometry args={[20, 20]} />
                <shadowMaterial transparent opacity={0.35} />
              </mesh>
              <OrbitControls makeDefault enableDamping />
              <Environment preset="city" />
            </Canvas>
          </div>

          <div className="flex items-center justify-between border-t border-slate-800 bg-slate-950/80 px-4 py-2">
            <div className="font-mono text-[11px] text-slate-400">
              pos({cubePos.x.toFixed(2)}, {cubePos.y.toFixed(2)}, {cubePos.z.toFixed(2)}) · rot({((cubeRot.y * 180) / Math.PI).toFixed(0)}°) · scale {cubeScale.toFixed(2)}x
            </div>
          </div>
        </section>

        <section className="mt-8 rounded-lg border border-slate-800 bg-slate-900/30 p-6">
          <h2 className="mb-4 font-mono text-xs uppercase tracking-[0.2em] text-slate-400">Próximas fases</h2>
          <ol className="space-y-2 text-sm text-slate-300">
            <Phase n="1" status="done" title="Botão na Home + rota /lab" />
            <Phase n="2" status="done" title="Cubo Three.js + Grid fino + Travar/Destravar + Joystick funcional" />
            <Phase n="3" status="done" title="Sistema de Apoio (face objeto + superfície alvo) - Tampo/Prateleira" />
            <Phase n="4" status="done" title="Sistema Direcional (face objeto + aresta alvo)" />
            <Phase n="5" title="Integração WebXR completa (@react-three/xr) — Passthrough real" />
            <Phase n="6" title="Migração da lógica redonda pro SteelXR XR Session principal" />
          </ol>
        </section>
      </main>
    </div>
  );
};

const Phase = ({ n, status, title }: { n: string; status?: "done" | "active"; title: string }) => (
  <li className="flex items-start gap-3">
    <span
      className={`flex h-6 w-6 shrink-0 items-center justify-center rounded-full font-mono text-xs ${
        status === "done" ? "bg-emerald-500/20 text-emerald-300" : status === "active" ? "bg-amber-500/20 text-amber-300" : "bg-slate-800 text-slate-500"
      }`}
    >
      {n}
    </span>
    <span className="text-slate-200">{title}</span>
  </li>
);

export default QuestCubeLab;
