import { useEffect, useRef, useMemo, useCallback, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import { useGLTF, Grid, Html, Line } from '@react-three/drei';
import { XR, createXRStore, useXR, XROrigin } from '@react-three/xr';
import * as THREE from 'three';
import { useModelStore } from '@/stores/useModelStore';
import { toast } from 'sonner';
import { ArrowLeft, Download, QrCode, Crosshair } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { generateMarkerDownloadURL } from '@/lib/trackingMarker';
import { XRHud } from '@/components/XRHud';
import { findNearestVertex } from '@/components/three/SmartMeasure';
import { XRHitTestPlacement } from '@/components/three/XRHitTestPlacement';

// --- Diagnóstico XR ---
console.log('[XR] Inicializando store...');
if (navigator.xr) {
  navigator.xr.isSessionSupported('immersive-ar').then((supported) => {
    console.log('[XR] immersive-ar suportado:', supported);
  });
}

const store = createXRStore({
  hand: { left: true, right: true },
  controller: { left: true, right: true },
});

// ─── XRModel ───────────────────────────────────────────
function XRModel({ url }: { url: string }) {
  const { scene } = useGLTF(url);
  const ref = useRef<THREE.Group>(null);
  const fineTuning = useModelStore((s) => s.fineTuning);
  const opacity = useModelStore((s) => s.opacity);
  const renderMode = useModelStore((s) => s.renderMode);
  const wireframeColor = useModelStore((s) => s.wireframeColor);
  const wireframeThickness = useModelStore((s) => s.wireframeThickness);
  const edgeThresholdAngle = useModelStore((s) => s.edgeThresholdAngle);
  const checklist = useModelStore((s) => s.checklist);

  const modelInfo = useMemo(() => {
    const box = new THREE.Box3().setFromObject(scene);
    const size = new THREE.Vector3();
    const center = new THREE.Vector3();
    box.getSize(size);
    box.getCenter(center);
    return { size, center };
  }, [scene]);

  useEffect(() => {
    const hasRejected = checklist.some(i => i.status === 'rejected');
    const allApproved = checklist.every(i => i.status === 'approved');

    scene.traverse((child) => {
      if (child instanceof THREE.Mesh) {
        if (Array.isArray(child.material)) {
          child.material = child.material.map(m => m.clone());
        } else {
          child.material = child.material.clone();
        }

        // Clean up previous edge lines
        const toRemove: THREE.Object3D[] = [];
        child.children.forEach(c => {
          if (c.userData.__edgeLine) toRemove.push(c);
        });
        toRemove.forEach(c => {
          if (c instanceof THREE.LineSegments) {
            c.geometry.dispose();
            (c.material as THREE.Material).dispose();
          }
          child.remove(c);
        });

        const materials = Array.isArray(child.material) ? child.material : [child.material];
        materials.forEach((mat: THREE.Material) => {
          if (mat instanceof THREE.MeshStandardMaterial) {
            if (renderMode === 'edges') {
              mat.visible = false;
            } else {
              mat.visible = true;
              mat.transparent = opacity < 1;
              mat.opacity = opacity;
              mat.wireframe = renderMode === 'wireframe';
              if (renderMode === 'wireframe') {
                mat.wireframeLinewidth = wireframeThickness;
                mat.color.set(wireframeColor);
              } else if (hasRejected) {
                mat.color.setHSL(0, 0.7, 0.5);
              } else if (allApproved) {
                mat.color.setHSL(0.38, 0.7, 0.45);
              } else {
                mat.color.set(0x8899aa);
              }
            }
            mat.needsUpdate = true;
          }
        });

        if (renderMode === 'edges' && child.geometry) {
          const edgesGeo = new THREE.EdgesGeometry(child.geometry, edgeThresholdAngle);
          const lineMat = new THREE.LineBasicMaterial({ color: wireframeColor, linewidth: wireframeThickness });
          const lineSegments = new THREE.LineSegments(edgesGeo, lineMat);
          lineSegments.userData.__edgeLine = true;
          child.add(lineSegments);
        }
      }
    });
  }, [scene, opacity, renderMode, checklist, wireframeColor, wireframeThickness, edgeThresholdAngle]);

  const rotYRad = (fineTuning.rotY * Math.PI) / 180;

  return (
    <group
      ref={ref}
      position={[
        -modelInfo.center.x + fineTuning.posX,
        -modelInfo.center.y + fineTuning.posY,
        -modelInfo.center.z + fineTuning.posZ,
      ]}
      rotation={[0, rotYRad, 0]}
    >
      <primitive object={scene} />
    </group>
  );
}

// ─── ControllerFineTuning ──────────────────────────────
function ControllerFineTuning({ freeMove }: { freeMove: boolean }) {
  const { setFineTuning } = useModelStore();
  const session = useXR((s) => s.session);

  useFrame(() => {
    if (!session) return;
    const inputSources = session.inputSources;
    if (!inputSources) return;

    let leftAxes: number[] | null = null;
    let rightAxes: number[] | null = null;
    let gripHeld = false;

    for (const source of inputSources) {
      const gp = source.gamepad;
      if (!gp) continue;
      const gripButton = gp.buttons[2];
      if (gripButton && gripButton.pressed) gripHeld = true;
      if (source.handedness === 'left' && gp.axes.length >= 4) {
        leftAxes = [gp.axes[2], gp.axes[3]];
      }
      if (source.handedness === 'right' && gp.axes.length >= 4) {
        rightAxes = [gp.axes[2], gp.axes[3]];
      }
    }

    // In freeMove mode, joystick always moves. Otherwise requires grip.
    if (!freeMove && !gripHeld) return;

    const posStep = 0.001;
    const rotStep = 0.1;
    const deadzone = 0.15;
    const modelStore = useModelStore.getState();
    const ft = { ...modelStore.fineTuning };

    if (leftAxes) {
      if (Math.abs(leftAxes[0]) > deadzone) ft.posX += leftAxes[0] * posStep;
      if (Math.abs(leftAxes[1]) > deadzone) ft.posY -= leftAxes[1] * posStep;
    }
    if (rightAxes) {
      if (Math.abs(rightAxes[1]) > deadzone) ft.posZ += rightAxes[1] * posStep;
      if (Math.abs(rightAxes[0]) > deadzone) ft.rotY += rightAxes[0] * rotStep;
    }

    setFineTuning(ft);
  });

  return null;
}

// ─── Measurement overlay (reused from ModelViewer) ─────
function XRMeasurementOverlay() {
  const measurements = useModelStore((s) => s.measurements);
  const measurePoints = useModelStore((s) => s.measurePoints);
  const snapPoint = useModelStore((s) => s.snapPoint);
  const measureMode = useModelStore((s) => s.measureMode);

  return (
    <>
      {measureMode && snapPoint && (
        <mesh position={[snapPoint.x, snapPoint.y, snapPoint.z]} rotation={[-Math.PI / 2, 0, 0]}>
          <ringGeometry args={[0.003, 0.005, 24]} />
          <meshBasicMaterial color="#eab308" side={THREE.DoubleSide} />
        </mesh>
      )}
      {measurePoints.length === 1 && (
        <mesh position={[measurePoints[0].x, measurePoints[0].y, measurePoints[0].z]}>
          <sphereGeometry args={[0.003, 16, 16]} />
          <meshBasicMaterial color="#e8a838" />
        </mesh>
      )}
      {measurements.map((m) => {
        const a: [number, number, number] = [m.pointA.x, m.pointA.y, m.pointA.z];
        const b: [number, number, number] = [m.pointB.x, m.pointB.y, m.pointB.z];
        const mid: [number, number, number] = [(a[0]+b[0])/2, (a[1]+b[1])/2, (a[2]+b[2])/2];
        return (
          <group key={m.id}>
            <mesh position={a}><sphereGeometry args={[0.003, 16, 16]} /><meshBasicMaterial color="#22c55e" /></mesh>
            <mesh position={b}><sphereGeometry args={[0.003, 16, 16]} /><meshBasicMaterial color="#22c55e" /></mesh>
            <Line points={[a, b]} color="#22c55e" lineWidth={2} />
            <Html position={mid} center distanceFactor={1} style={{ pointerEvents: 'none' }}>
              <div className="rounded bg-card/95 border border-primary/50 px-2 py-0.5 shadow-lg backdrop-blur-sm">
                <span className="font-mono text-[11px] font-bold text-primary whitespace-nowrap">
                  {m.distanceMM.toFixed(1)} mm
                </span>
              </div>
            </Html>
          </group>
        );
      })}
    </>
  );
}

// ─── Snap handler for XR raycasting ────────────────────
function XRSnapHandler() {
  const { camera, scene, gl } = useThree();
  const measureMode = useModelStore((s) => s.measureMode);
  const setSnapPoint = useModelStore((s) => s.setSnapPoint);
  const addMeasurePoint = useModelStore((s) => s.addMeasurePoint);
  const snapPoint = useModelStore((s) => s.snapPoint);
  const raycaster = useMemo(() => new THREE.Raycaster(), []);
  const mouse = useMemo(() => new THREE.Vector2(), []);

  useEffect(() => {
    if (!measureMode) return;
    const onMove = (e: MouseEvent) => {
      const rect = gl.domElement.getBoundingClientRect();
      mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
      mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
    };
    gl.domElement.addEventListener('pointermove', onMove);
    return () => gl.domElement.removeEventListener('pointermove', onMove);
  }, [gl, mouse, measureMode]);

  useFrame(() => {
    if (!measureMode) { setSnapPoint(null); return; }
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(scene.children, true);
    const hit = intersects.find(i => {
      const obj = i.object;
      if (obj instanceof THREE.GridHelper) return false;
      if (obj instanceof THREE.Mesh && (obj.geometry instanceof THREE.SphereGeometry || obj.geometry instanceof THREE.RingGeometry)) return false;
      if (obj.userData.__edgeLine) return false;
      return obj instanceof THREE.Mesh;
    });
    if (hit && hit.object instanceof THREE.Mesh) {
      const canvas = gl.domElement;
      const snap = findNearestVertex(hit.object, hit.point, camera, { width: canvas.clientWidth, height: canvas.clientHeight }, 10);
      setSnapPoint(snap ? { x: snap.x, y: snap.y, z: snap.z } : null);
    } else {
      setSnapPoint(null);
    }
  });

  // Click to measure
  useEffect(() => {
    if (!measureMode) return;
    const onClick = (e: MouseEvent) => {
      if (snapPoint) {
        addMeasurePoint({ x: snapPoint.x, y: snapPoint.y, z: snapPoint.z });
        return;
      }
      const rect = gl.domElement.getBoundingClientRect();
      mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
      mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
      raycaster.setFromCamera(mouse, camera);
      const intersects = raycaster.intersectObjects(scene.children, true);
      const hit = intersects.find(i => i.object instanceof THREE.Mesh && !i.object.userData.__edgeLine);
      if (hit) addMeasurePoint({ x: hit.point.x, y: hit.point.y, z: hit.point.z });
    };
    gl.domElement.addEventListener('click', onClick);
    return () => gl.domElement.removeEventListener('click', onClick);
  }, [measureMode, snapPoint, gl, camera, scene, raycaster, mouse, addMeasurePoint]);

  useEffect(() => {
    gl.domElement.style.cursor = measureMode ? 'crosshair' : 'grab';
    return () => { gl.domElement.style.cursor = 'grab'; };
  }, [measureMode, gl]);

  return null;
}

// ─── XR Grid ───────────────────────────────────────────
function XRGrid() {
  const showGrid = useModelStore((s) => s.showGrid);
  if (!showGrid) return null;
  return (
    <Grid
      infiniteGrid
      cellSize={0.01}
      sectionSize={0.1}
      cellThickness={0.5}
      sectionThickness={1}
      cellColor="#334155"
      sectionColor="#475569"
      fadeDistance={5}
      fadeStrength={1}
    />
  );
}

// ImageTrackingAnchor removed — replaced by XRHitTestPlacement

// ─── XRSession Page ────────────────────────────────────
const XRSession = () => {
  const navigate = useNavigate();
  const { model, anchorMode, setAnchorMode } = useModelStore();
  const [inXR, setInXR] = useState(false);
  const [freeMove, setFreeMove] = useState(true);
  const [placementMode, setPlacementMode] = useState(true); // start in placement mode
  const [snapToPlanes, setSnapToPlanes] = useState(true);

  useEffect(() => {
    if (!model) navigate('/');
  }, [model, navigate]);

  useEffect(() => {
    const unsubscribe = store.subscribe((state) => {
      const session = state.session;
      if (session && !inXR) {
        console.log('[XR] ✅ Sessão AR ativa!');
        setInXR(true);
        setAnchorMode('manual');
        toast.success('Sessão AR iniciada!');
        session.addEventListener('end', () => {
          console.log('[XR] ❌ Sessão AR encerrada');
          setInXR(false);
        });
      }
    });
    return unsubscribe;
  }, [inXR, setAnchorMode]);

  const handleDownloadMarker = useCallback(async () => {
    const url = await generateMarkerDownloadURL();
    const a = document.createElement('a');
    a.href = url;
    a.download = 'TrackSteelXR_Marker.png';
    a.click();
    URL.revokeObjectURL(url);
    toast.success('Marcador baixado — Imprima em 15×15cm');
  }, []);

  if (!model) return null;

  return (
    <div className="flex h-screen flex-col bg-background">
      {/* Header */}
      <header className="flex items-center justify-between border-b bg-card px-4 py-3 z-10">
        <div className="flex items-center gap-3">
          <Button variant="ghost" size="icon" onClick={() => navigate('/viewer')}>
            <ArrowLeft className="h-5 w-5" />
          </Button>
          <h1 className="font-mono text-sm font-semibold text-foreground">
            Modo <span className="text-primary">XR Imersivo</span>
          </h1>
        </div>

        <div className="flex items-center gap-2">
          {!inXR && (
            <>
              <Button variant="outline" size="sm" className="gap-1.5" onClick={handleDownloadMarker}>
                <Download className="h-3.5 w-3.5" />
                <span className="font-mono text-xs">Marcador</span>
              </Button>
              <Button className="gap-2 glow-primary" onClick={() => {
                console.log('[XR] Botão AR clicado');
                store.enterAR().catch((e) => console.error('[XR] enterAR rejeitado:', e));
              }}>
                Iniciar Sessão AR
              </Button>
            </>
          )}
          {inXR && (
            <span className="font-mono text-xs text-primary flex items-center gap-1.5">
              <span className="h-2 w-2 rounded-full bg-primary animate-pulse" />
              XR Ativo
            </span>
          )}
        </div>
      </header>

      {/* 3D Canvas */}
      <div className="flex-1 relative">
        <Canvas
          gl={{ antialias: true, alpha: true, powerPreference: 'high-performance', preserveDrawingBuffer: true }}
          camera={{ position: [0, 1.6, 0], fov: 50, near: 0.01, far: 100 }}
          className="!bg-transparent"
          onCreated={({ gl, invalidate }) => {
            gl.setPixelRatio(Math.min(window.devicePixelRatio, 1.5));
            gl.setClearColor(0x000000, 0);
            const loop = () => { invalidate(); requestAnimationFrame(loop); };
            loop();
          }}
        >
          <XR store={store}>
            <ambientLight intensity={0.8} />
            <directionalLight position={[3, 5, 3]} intensity={1.2} />
            <directionalLight position={[-3, 3, -3]} intensity={0.4} />

            <XROrigin />

            <XRHitTestPlacement
              placementMode={placementMode}
              snapToPlanes={snapToPlanes}
              onPlace={() => {
                setPlacementMode(false);
                toast.success('Modelo posicionado na superfície!');
              }}
            >
              <XRModel url={model.url} />
            </XRHitTestPlacement>

            <XRMeasurementOverlay />
            <XRSnapHandler />
            <XRGrid />
            <ControllerFineTuning freeMove={freeMove} />
          </XR>
        </Canvas>

        {/* Floating HUD overlay with all controls */}
        <XRHud
          freeMove={freeMove}
          onToggleFreeMove={() => setFreeMove(!freeMove)}
          placementMode={placementMode}
          onTogglePlacement={() => setPlacementMode(!placementMode)}
          snapToPlanes={snapToPlanes}
          onToggleSnap={() => setSnapToPlanes(!snapToPlanes)}
        />
      </div>
    </div>
  );
};

export default XRSession;
