import { useRef, useState } from "react";
import * as THREE from "three";

import { assemblyAlertCounts } from "../app/geometryReport";
import { useGeometryReport } from "../app/useGeometryReport";
import type { BrepGraphSnapshot, CadGenerationProgress, PickedFace, ViewerLoadState } from "../appTypes";
import { resolveAssetFormat } from "../appUtils";
import type { SolverFieldDescriptor } from "../types";
import { ViewerOverlays } from "./viewer/ViewerOverlays";
import {
  useThreeScene,
  useAssetLoader,
  useFacePicker,
  useFaceIdentityMaps,
  useHighlightOverlay,
  useAssemblyCheckOverlay,
} from "./viewer/hooks";

export function ModelViewer({
  assetUrl,
  assetFormat,
  fieldDescriptor,
  projectId,
  pickedFaces,
  onAddPickedFace,
  onClearPickedFaces,
  onCopyPointer,
  cadGenerationProgress,
  highlightedFaceIds,
  brepSnapshot,
  onClearHighlightedFaces,
}: {
  assetUrl?: string | null;
  assetFormat?: string | null;
  fieldDescriptor?: SolverFieldDescriptor | null;
  projectId?: string | null;
  pickedFaces: PickedFace[];
  onAddPickedFace(face: PickedFace): void;
  onClearPickedFaces(): void;
  onCopyPointer(text: string): void;
  cadGenerationProgress: CadGenerationProgress | null;
  highlightedFaceIds: Set<string>;
  brepSnapshot: BrepGraphSnapshot | null;
  onClearHighlightedFaces(): void;
}) {
  const hostRef = useRef<HTMLDivElement | null>(null);
  const objectRef = useRef<THREE.Object3D | null>(null);
  const [objectReadyKey, setObjectReadyKey] = useState(0);
  const [viewerState, setViewerState] = useState<{ status: ViewerLoadState; detail: string }>({
    status: "idle",
    detail: "Waiting for preview asset",
  });
  const [tooltipFace, setTooltipFace] = useState<PickedFace | null>(null);
  const [showAssemblyCheck, setShowAssemblyCheck] = useState(false);

  const { geometryReport } = useGeometryReport({
    selectedId: projectId ?? null,
    geometryVersion: assetUrl ?? null,
  });
  const assemblyAlerts = assemblyAlertCounts(geometryReport);
  const resolvedAssetFormat = resolveAssetFormat(assetUrl, assetFormat);

  // 1. Three.js scene lifecycle
  const { sceneRef, cameraRef, controlsRef, highlightGroupRef, assemblyGroupRef } =
    useThreeScene(hostRef);

  // 2. Asset loading
  useAssetLoader(
    sceneRef,
    cameraRef,
    controlsRef,
    objectRef,
    assetUrl,
    assetFormat,
    fieldDescriptor,
    () => setObjectReadyKey((k) => k + 1),
    setViewerState,
  );

  // 3. Face identity maps (viewer↔model transform + primitive↔face)
  const { displayTransformRef, primitiveFaceRef, faceMeshesRef } = useFaceIdentityMaps(
    objectRef,
    brepSnapshot,
    resolvedAssetFormat,
    objectReadyKey,
  );

  // 4. Face picking (raycast + backend fallback)
  useFacePicker(
    hostRef,
    objectRef,
    cameraRef,
    primitiveFaceRef,
    displayTransformRef,
    projectId,
    onAddPickedFace,
    setTooltipFace,
  );

  // 5. Highlight overlay
  useHighlightOverlay(
    highlightGroupRef,
    faceMeshesRef,
    highlightedFaceIds,
    brepSnapshot,
    objectRef,
    displayTransformRef,
    objectReadyKey,
  );

  // 6. Assembly-check overlay
  useAssemblyCheckOverlay(
    assemblyGroupRef,
    showAssemblyCheck,
    geometryReport,
    displayTransformRef,
    objectReadyKey,
  );

  return (
    <div className="viewer-canvas-shell">
      <div className="viewer-canvas" ref={hostRef} />
      {assemblyAlerts.total > 0 && (
        <button
          type="button"
          className="viewer-assembly-toggle"
          onClick={() => setShowAssemblyCheck((value) => !value)}
          title="Highlight floating parts and broken left/right symmetry detected in the geometry"
          style={{
            position: "absolute",
            top: 8,
            left: 8,
            zIndex: 5,
            padding: "4px 10px",
            fontSize: 12,
            borderRadius: 6,
            border: "1px solid #3a3a3a",
            background: showAssemblyCheck ? "#7f1d1d" : "rgba(20,20,20,0.78)",
            color: "#f5f5f5",
            cursor: "pointer",
          }}
        >
          {showAssemblyCheck ? "Hide" : "Show"} assembly check ({assemblyAlerts.total})
        </button>
      )}
      <ViewerOverlays
        viewerState={viewerState}
        tooltipFace={tooltipFace}
        pickedFaces={pickedFaces}
        highlightedFaceIds={highlightedFaceIds}
        cadGenerationProgress={cadGenerationProgress}
        onCopyPointer={onCopyPointer}
        onClearPickedFaces={onClearPickedFaces}
        onClearHighlightedFaces={onClearHighlightedFaces}
      />
    </div>
  );
}
