import { useEffect, useRef, useCallback, useState } from "react";
import "@kitware/vtk.js/Rendering/Profiles/Volume";
import "@kitware/vtk.js/Rendering/Profiles/Geometry";
import "@kitware/vtk.js/Rendering/Misc/RenderingAPIs";

import vtkBoundingBox from "@kitware/vtk.js/Common/DataModel/BoundingBox";
import vtkColorTransferFunction from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction";
import vtkImageResliceMapper from "@kitware/vtk.js/Rendering/Core/ImageResliceMapper";
import vtkImageSlice from "@kitware/vtk.js/Rendering/Core/ImageSlice";
import vtkInteractorStyleImage from "@kitware/vtk.js/Interaction/Style/InteractorStyleImage";
import vtkInteractorStyleTrackballCamera from "@kitware/vtk.js/Interaction/Style/InteractorStyleTrackballCamera";
import vtkPiecewiseFunction from "@kitware/vtk.js/Common/DataModel/PiecewiseFunction";
import vtkPlane from "@kitware/vtk.js/Common/DataModel/Plane";
import vtkRenderWindow from "@kitware/vtk.js/Rendering/Core/RenderWindow";
import vtkRenderWindowInteractor from "@kitware/vtk.js/Rendering/Core/RenderWindowInteractor";
import vtkRenderer from "@kitware/vtk.js/Rendering/Core/Renderer";
import vtkVolume from "@kitware/vtk.js/Rendering/Core/Volume";
import vtkVolumeMapper from "@kitware/vtk.js/Rendering/Core/VolumeMapper";
import vtkOpenGLRenderWindow from "@kitware/vtk.js/Rendering/OpenGL/RenderWindow";

import type { ViewOrientation, Active2DView } from "./ViewRotationControls";

interface QuadViewRendererProps {
  dicomData: any;
  windowWidth: number;
  windowLevel: number;
  opacity: number;
  isLoading?: boolean;
  onRotate3D?: (orientation: ViewOrientation) => void;
  active2DView?: Active2DView;
  currentOrientation?: ViewOrientation;
}

interface ViewportContainer {
  element: HTMLDivElement;
  id: number;
  label: string;
}

type ExpandedView = null | 0 | 1 | 2 | 3;

export const QuadViewRenderer = ({
  dicomData,
  windowWidth,
  windowLevel,
  opacity,
  isLoading = false,
  onRotate3D,
  active2DView,
  currentOrientation,
}: QuadViewRendererProps) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const [expandedView, setExpandedView] = useState<ExpandedView>(null);
  
  const isMouseDownRef = useRef(false);
  const activeViewportRef = useRef<HTMLElement | null>(null);

  // Rotation angle state for each view
  const rotationAnglesRef = useRef<{ [key: string]: number }>({
    axial: 0,
    coronal: 0,
    sagittal: 0,
  });

  const contextRef = useRef<{
    renderWindow: any;
    renderWindowView: any;
    interactor: any;
    renderers: any[];
    containers: ViewportContainer[];
    imageSliceActors: any[];
    slicePlanes: any[];
    volumeActor: any;
    ctf: any;
    pf: any;
    iStyle: any;
    tStyle: any;
  } | null>(null);
  
  const loadedDataRef = useRef<any>(null);

  // --- Helper Functions ---

  const resizeViewportContainer = useCallback((
    _view: HTMLElement,
    ren: any,
    element: HTMLElement
  ) => {
    const vp = ren.getViewport();
    const border = 2;
    // Position the frame as PERCENTAGES of the container. The WebGL canvas fills the
    // container (style width:100%), so a normalized VTK viewport [vp0,vp1,vp2,vp3] maps
    // to the same %-rect and lines up with the rendered content. Computing px from
    // getBoundingClientRect() was fragile: the viewer opens in a dialog that animates
    // with transform: scale(.95→1), and ResizeObserver does NOT fire on transform
    // changes — so a rect captured mid-zoom froze the frame ~5% small/offset while the
    // canvas stretched to fill, leaving the slice spilling past the top/right borders.
    // Percentages track the canvas under any transform or resize. (box-sizing:border-box
    // is set on the element, so the 2px frame is drawn inside the viewport rect.)
    element.style.position = "absolute";
    element.style.left = `${vp[0] * 100}%`;
    element.style.bottom = `${vp[1] * 100}%`;
    element.style.width = `${(vp[2] - vp[0]) * 100}%`;
    element.style.height = `${(vp[3] - vp[1]) * 100}%`;
    element.style.border = `solid ${border}px hsl(var(--border))`;
    element.style.borderRadius = "6px";
  }, []);

  const bindInteractor = useCallback((interactor: any, el: HTMLElement | null) => {
    if (!contextRef.current || !containerRef.current) return;
    const { iStyle, tStyle } = contextRef.current;
    const full = containerRef.current;

    // Switch interaction STYLE per active pane (3D → trackball, 2D → image), but
    // always bind events to the full canvas container — never a per-pane overlay —
    // so VTK's findPokedRenderer resolves the cursor to the correct viewport in
    // full-canvas coordinates (sub-region binding made 3D drags drive the 2D panes).
    if (el) {
      interactor.setInteractorStyle(el.dataset.viewId === "3" ? tStyle : iStyle);
    }
    if (interactor.getContainer() !== full) {
      if (interactor.getContainer()) {
        interactor.unbindEvents();
      }
      interactor.bindEvents(full);
    }
  }, []);

  const getViewports = useCallback((expanded: ExpandedView): [number, number, number, number][] => {
    if (expanded === null) {
      return [
        [0.01, 0.51, 0.49, 0.99],  // top-left (Axial)
        [0.51, 0.51, 0.99, 0.99], // top-right (Coronal)
        [0.01, 0.01, 0.49, 0.49],  // bottom-left (Sagittal)
        [0.51, 0.01, 0.99, 0.49], // bottom-right (3D)
      ];
    } else {
      const mainViewport: [number, number, number, number] = [0.01, 0.01, 0.74, 0.99];
      const sideViewports: [number, number, number, number][] = [
        [0.75, 0.67, 0.99, 0.99],
        [0.75, 0.34, 0.99, 0.66],
        [0.75, 0.01, 0.99, 0.33],
      ];
      
      const result: [number, number, number, number][] = [];
      let sideIndex = 0;
      for (let i = 0; i < 4; i++) {
        if (i === expanded) {
          result.push(mainViewport);
        } else {
          result.push(sideViewports[sideIndex]);
          sideIndex++;
        }
      }
      return result;
    }
  }, []);

  const resize = useCallback(() => {
    if (!containerRef.current || !contextRef.current) return;
    
    const rect = containerRef.current.getBoundingClientRect();
    const { renderWindowView, renderers, containers, renderWindow } = contextRef.current;
    
    renderWindowView.setSize(rect.width, rect.height);
    
    containers.forEach((c) => {
      resizeViewportContainer(containerRef.current!, renderers[c.id], c.element);
    });
    
    renderWindow.render();
  }, [resizeViewportContainer]);

  // --- Logic 1: 3D Rotation Functionality ---
  
  const rotate3DView = useCallback((orientation: ViewOrientation) => {
    if (!contextRef.current || !dicomData?.imageData) return;
    
    const { renderers, renderWindow } = contextRef.current;
    const bounds = dicomData.imageData.getBounds();
    const center = vtkBoundingBox.getCenter(bounds);
    const diagonal = vtkBoundingBox.getDiagonalLength(bounds);
    const distance = (diagonal ?? 0) * 1.5;
    
    const cam3d = renderers[3].getActiveCamera();
    
    switch (orientation) {
      case "anterior":
        cam3d.setPosition(center[0], center[1] - distance, center[2]);
        cam3d.setFocalPoint(...center);
        cam3d.setViewUp(0, 0, 1);
        break;
      case "posterior":
        cam3d.setPosition(center[0], center[1] + distance, center[2]);
        cam3d.setFocalPoint(...center);
        cam3d.setViewUp(0, 0, 1);
        break;
      case "left-lateral":
        cam3d.setPosition(center[0] - distance, center[1], center[2]);
        cam3d.setFocalPoint(...center);
        cam3d.setViewUp(0, 0, 1);
        break;
      case "right-lateral":
        cam3d.setPosition(center[0] + distance, center[1], center[2]);
        cam3d.setFocalPoint(...center);
        cam3d.setViewUp(0, 0, 1);
        break;
      case "superior":
        cam3d.setPosition(center[0], center[1], center[2] + distance);
        cam3d.setFocalPoint(...center);
        cam3d.setViewUp(0, 1, 0);
        break;
      case "inferior":
        cam3d.setPosition(center[0], center[1], center[2] - distance);
        cam3d.setFocalPoint(...center);
        cam3d.setViewUp(0, -1, 0);
        break;
      default:
        cam3d.setPosition(center[0], center[1] - distance, center[2]);
        cam3d.setFocalPoint(...center);
        cam3d.setViewUp(0, 0, 1);
    }
    
    renderWindow.render();
    onRotate3D?.(orientation);
  }, [dicomData, onRotate3D]);

  // --- Logic 2: Robust 2D Rotation Logic (Rodrigues' Formula) ---
  const rotate2DView = useCallback((view: Active2DView, direction: "cw" | "ccw") => {
    if (!contextRef.current || !view || !dicomData?.imageData) return;
    
    const { renderers, renderWindow } = contextRef.current;
    const bounds = dicomData.imageData.getBounds();
    const center = vtkBoundingBox.getCenter(bounds);
    
    // Rotation step in degrees
    const rotationStep = direction === "cw" ? 90 : -90;
    
    // Update rotation angle
    rotationAnglesRef.current[view] = (rotationAnglesRef.current[view] + rotationStep) % 360;
    const angle = rotationAnglesRef.current[view] * (Math.PI / 180);
    
    let cam: any;
    let viewDirection: [number, number, number];
    let baseViewUp: [number, number, number];
    
    // Get the appropriate renderer and base view up vector
    if (view === "axial") {
      cam = renderers[0].getActiveCamera();
      viewDirection = [0, 0, 1]; // Looking along Z axis
      baseViewUp = [0, -1, 0];
    } else if (view === "coronal") {
      cam = renderers[1].getActiveCamera();
      viewDirection = [0, 1, 0]; // Looking along Y axis
      baseViewUp = [0, 0, 1];
    } else if (view === "sagittal") {
      cam = renderers[2].getActiveCamera();
      viewDirection = [1, 0, 0]; // Looking along X axis
      baseViewUp = [0, 0, 1];
    } else {
      return;
    }
    
    // Get current view up vector from camera
    const currentViewUp = cam.getViewUp();
    
    // Calculate rotation axis (the view direction)
    const axis = viewDirection;
    
    // Rotate the current view up vector around the view direction axis
    // Using Rodrigues' rotation formula
    const cos = Math.cos(angle);
    const sin = Math.sin(angle);
    const dot = currentViewUp[0] * axis[0] + currentViewUp[1] * axis[1] + currentViewUp[2] * axis[2];
    
    // Project view up onto the plane perpendicular to the axis
    const projX = currentViewUp[0] - dot * axis[0];
    const projY = currentViewUp[1] - dot * axis[1];
    const projZ = currentViewUp[2] - dot * axis[2];
    
    // Normalize the projection
    const projLen = Math.sqrt(projX * projX + projY * projY + projZ * projZ);
    if (projLen < 1e-6) {
      // If projection is too small, use base view up
      const rotatedViewUp: [number, number, number] = [
        baseViewUp[0] * cos - (axis[1] * baseViewUp[2] - axis[2] * baseViewUp[1]) * sin,
        baseViewUp[1] * cos - (axis[2] * baseViewUp[0] - axis[0] * baseViewUp[2]) * sin,
        baseViewUp[2] * cos - (axis[0] * baseViewUp[1] - axis[1] * baseViewUp[0]) * sin
      ];
      cam.setFocalPoint(...center);
      cam.setViewUp(...rotatedViewUp);
    } else {
      // Normalize projection
      const ux = projX / projLen;
      const uy = projY / projLen;
      const uz = projZ / projLen;
      
      // Calculate perpendicular vector (cross product of axis and projection)
      const perpX = axis[1] * uz - axis[2] * uy;
      const perpY = axis[2] * ux - axis[0] * uz;
      const perpZ = axis[0] * uy - axis[1] * ux;
      
      // Rotate using Rodrigues' formula
      const rotatedViewUp: [number, number, number] = [
        ux * cos + perpX * sin + dot * axis[0],
        uy * cos + perpY * sin + dot * axis[1],
        uz * cos + perpZ * sin + dot * axis[2]
      ];
      
      cam.setFocalPoint(...center);
      cam.setViewUp(...rotatedViewUp);
    }
    
    cam.orthogonalizeViewUp();
    renderWindow.render();
  }, [dicomData]);

  // --- Logic 3: Handle currentOrientation prop changes ---
  useEffect(() => {
    if (!contextRef.current || !currentOrientation || !active2DView) return;
    
    // This handles 2D rotations triggered by the toolbar/external state
    if (currentOrientation === "rotate-cw") {
      rotate2DView(active2DView, "cw");
    } else if (currentOrientation === "rotate-ccw") {
      rotate2DView(active2DView, "ccw");
    }
  }, [currentOrientation, active2DView, rotate2DView]);

  // --- Logic 4: Standard Medical View Orientations (2D Initialization) ---
  useEffect(() => {
    if (!contextRef.current || !dicomData?.imageData) return;
    
    const { renderers, renderWindow } = contextRef.current;
    const bounds = dicomData.imageData.getBounds();
    const center = vtkBoundingBox.getCenter(bounds);
    
    // Axial: Looking from head to toe, patient's right on left (Radiological)
    const axialCam = renderers[0].getActiveCamera();
    axialCam.setPosition(center[0], center[1], center[2] - 1);
    axialCam.setFocalPoint(center[0], center[1], center[2]);
    axialCam.setViewUp(0, -1, 0); // Inverted Y for radiological convention
    
    // Coronal: Looking from front to back, patient's right on left
    const coronalCam = renderers[1].getActiveCamera();
    coronalCam.setPosition(center[0], center[1] - 1, center[2]);
    coronalCam.setFocalPoint(center[0], center[1], center[2]);
    coronalCam.setViewUp(0, 0, 1);
    
    // Sagittal: Looking from left to right, anterior at top
    const sagittalCam = renderers[2].getActiveCamera();
    sagittalCam.setPosition(center[0] - 1, center[1], center[2]);
    sagittalCam.setFocalPoint(center[0], center[1], center[2]);
    sagittalCam.setViewUp(0, 0, 1);
    
    renderWindow.render();
  }, [dicomData]);

  // --- Logic 5: Handle External Rotation Requests via Ref (Imperative) ---
  useEffect(() => {
    if (!onRotate3D || !contextRef.current) return;
    
    const handleRotate = (orientation: ViewOrientation) => {
      // Integrated Logic from Code 1: 2D Rotations
      if (orientation === "rotate-cw" && active2DView) {
        rotate2DView(active2DView, "cw");
      } else if (orientation === "rotate-ccw" && active2DView) {
        rotate2DView(active2DView, "ccw");
      } else if (orientation === "axial" || orientation === "coronal" || orientation === "sagittal") {
        // Reset rotation angle for that view if explicitly selected
        rotationAnglesRef.current[orientation] = 0;
      } else {
        // Handle 3D rotations
        rotate3DView(orientation);
      }
    };

    // Store handler for external access
    (contextRef.current as any).handleRotate = handleRotate;
    (contextRef.current as any).rotate3D = rotate3DView;
  }, [onRotate3D, rotate3DView, rotate2DView, active2DView]);

  // --- Logic 6: Reset rotation when view changes ---
  useEffect(() => {
    if (active2DView) {
      rotationAnglesRef.current[active2DView] = 0;
    }
  }, [active2DView]);

  // --- Logic 7: Viewport Expansion Handling ---
  useEffect(() => {
    if (!contextRef.current) return;
    
    const { renderers, containers, renderWindow, renderWindowView } = contextRef.current;
    const viewports = getViewports(expandedView);
    
    renderers.forEach((ren, i) => {
      ren.setViewport(viewports[i][0], viewports[i][1], viewports[i][2], viewports[i][3]);
    });
    
    if (containerRef.current) {
      const rect = containerRef.current.getBoundingClientRect();
      renderWindowView.setSize(rect.width, rect.height);
      
      containers.forEach((c) => {
        resizeViewportContainer(containerRef.current!, renderers[c.id], c.element);
      });
    }

    // Re-fit every view to its new viewport so the slice / volume FILLS the resized pane.
    // Without this an expanded pane keeps the small framing it had as a 2×2 quadrant
    // (content stuck tiny in a corner). resetCamera preserves each camera's direction +
    // view-up — so orientation and any 3D rotation are kept — and only re-centers + rescales.
    renderers.forEach((ren) => ren.resetCamera());

    renderWindow.render();
  }, [expandedView, getViewports, resizeViewportContainer]);

  // --- Logic 8: VTK Initialization ---
  useEffect(() => {
    if (!containerRef.current) return;

    const renderWindow = vtkRenderWindow.newInstance();
    const renderWindowView = vtkOpenGLRenderWindow.newInstance();
    
    const rect = containerRef.current.getBoundingClientRect();
    renderWindowView.setSize(rect.width, rect.height);
    renderWindow.addView(renderWindowView);
    renderWindowView.setContainer(containerRef.current);

    const iStyle = vtkInteractorStyleImage.newInstance();
    const tStyle = vtkInteractorStyleTrackballCamera.newInstance();

    const interactor = vtkRenderWindowInteractor.newInstance();
    interactor.setView(renderWindowView);
    interactor.initialize();
    interactor.setInteractorStyle(tStyle);

    const renderers: any[] = [];
    const containers: ViewportContainer[] = [];
    const labels = ["AXIAL", "CORONAL", "SAGITTAL", "3D"];

    // Create 4 viewports in a 2x2 grid
    const viewports: [number, number, number, number][] = [
      [0.01, 0.51, 0.49, 0.99],  // top-left
      [0.51, 0.51, 0.99, 0.99], // top-right
      [0.01, 0.01, 0.49, 0.49],  // bottom-left
      [0.51, 0.01, 0.99, 0.49], // bottom-right (3D)
    ];

    // Pin / unpin all VTK interaction to a single pane for the lifetime of a drag.
    // VTK re-resolves the "poked" renderer on EVERY mouse-move (findPokedRenderer),
    // and it skips renderers whose getInteractive() is false — so marking the other
    // panes non-interactive while a drag is in flight keeps the gesture on the pane
    // it started in (e.g. a 3D-pane rotate never leaks into axial/coronal/sagittal).
    const confineInteractionTo = (activeId: number) => {
      renderers.forEach((ren, idx) => ren.setInteractive(idx === activeId));
    };
    const releaseInteraction = () => {
      renderers.forEach((ren) => ren.setInteractive(true));
    };

    for (let i = 0; i < 4; i++) {
      // Black background for 2D views, dark gray for 3D
      const bgColor: [number, number, number] = i === 3 ? [0.1, 0.1, 0.15] : [0, 0, 0];
      const ren = vtkRenderer.newInstance({ background: bgColor });
      ren.setViewport(viewports[i][0], viewports[i][1], viewports[i][2], viewports[i][3]);

      const container = document.createElement("div");
      container.dataset.viewId = String(i);
      container.style.position = "absolute";
      container.style.boxSizing = "border-box";
      container.style.overflow = "hidden";
      container.style.borderRadius = "6px";
      
      containerRef.current.appendChild(container);

      // Add label
      const label = document.createElement("div");
      label.textContent = labels[i];
      label.style.position = "absolute";
      label.style.top = "8px";
      label.style.left = "8px";
      label.style.color = "rgba(255, 255, 255, 0.7)";
      label.style.fontSize = "11px";
      label.style.fontWeight = "600";
      label.style.letterSpacing = "0.05em";
      label.style.textTransform = "uppercase";
      label.style.zIndex = "10";
      label.style.pointerEvents = "none";
      label.style.textShadow = "0 1px 2px rgba(0,0,0,0.8)";
      container.appendChild(label);

      // Handle mouse down - lock interactor to this viewport
      container.addEventListener("mousedown", (e) => {
        isMouseDownRef.current = true;
        activeViewportRef.current = container;
        confineInteractionTo(Number(container.dataset.viewId));
        bindInteractor(interactor, container);
        // Toggle expand on double-click — detected HERE via e.detail===2 (the 2nd press of
        // a double-click) rather than a "dblclick" listener, because VTK's interactor takes
        // pointer capture on press, so the native click/dblclick land on the parent canvas
        // container, NOT this per-pane div. mousedown still fires on the div, so this is the
        // only place a per-pane double-click is observable.
        if (e.detail === 2) {
          const viewId = Number(container.dataset.viewId);
          setExpandedView((prev) => (prev === viewId ? null : (viewId as ExpandedView)));
        }
      });

      // Handle mouse up - unlock interactor
      container.addEventListener("mouseup", () => {
        isMouseDownRef.current = false;
        activeViewportRef.current = null;
        releaseInteraction();
      });

      // Handle mouse leave - only unbind if not dragging
      container.addEventListener("mouseleave", () => {
        if (!isMouseDownRef.current) {
          bindInteractor(interactor, null);
        }
      });

      // Handle pointer enter - only bind if not dragging and no active viewport
      container.addEventListener("pointerenter", () => {
        if (!isMouseDownRef.current && !activeViewportRef.current) {
          bindInteractor(interactor, container);
        }
      });

      // Handle pointer leave - only unbind if not dragging
      container.addEventListener("pointerleave", () => {
        if (!isMouseDownRef.current) {
          bindInteractor(interactor, null);
        }
      });

      renderWindow.addRenderer(ren);
      renderers.push(ren);
      containers.push({ element: container, id: i, label: labels[i] });
      
      resizeViewportContainer(containerRef.current, ren, container);
    }

    // Handle global mouse up to catch releases outside viewports
    const handleGlobalMouseUp = () => {
      isMouseDownRef.current = false;
      activeViewportRef.current = null;
      releaseInteraction();
    };
    window.addEventListener("mouseup", handleGlobalMouseUp);

    // Create slice mappers and planes
    const slicePlanes: any[] = [];
    const imageSliceActors: any[] = [];

    // Axial plane (Z normal)
    const axialPlane = vtkPlane.newInstance();
    axialPlane.setNormal(0, 0, 1);
    slicePlanes.push(axialPlane);

    // Coronal plane (Y normal)
    const coronalPlane = vtkPlane.newInstance();
    coronalPlane.setNormal(0, 1, 0);
    slicePlanes.push(coronalPlane);

    // Sagittal plane (X normal)
    const sagittalPlane = vtkPlane.newInstance();
    sagittalPlane.setNormal(1, 0, 0);
    slicePlanes.push(sagittalPlane);

    // Create 2D slice actors (grayscale; window/level driven)
    for (let i = 0; i < 3; i++) {
      const mapper = vtkImageResliceMapper.newInstance();
      mapper.setSlicePlane(slicePlanes[i]);

      const actor = vtkImageSlice.newInstance();
      actor.setMapper(mapper);

      const sliceCtf = vtkColorTransferFunction.newInstance();
      // Placeholder points; updated by window/level effect
      sliceCtf.addRGBPoint(0, 0, 0, 0);
      sliceCtf.addRGBPoint(1, 1, 1, 1);

      actor.getProperty().setRGBTransferFunction(0, sliceCtf);
      actor.getProperty().setColorWindow(windowWidth);
      actor.getProperty().setColorLevel(windowLevel);

      renderers[i].addActor(actor);

      const cam = renderers[i].getActiveCamera();
      cam.setParallelProjection(true);

      if (i === 0) {
        // Axial
        cam.setPosition(0, 0, -1);
        cam.setViewUp(0, -1, 0);
      } else if (i === 1) {
        // Coronal
        cam.setPosition(0, -1, 0);
        cam.setViewUp(0, 0, 1);
      } else {
        // Sagittal
        cam.setPosition(-1, 0, 0);
        cam.setViewUp(0, 0, 1);
      }

      imageSliceActors.push({ actor, mapper, ctf: sliceCtf });
    }

    // Volume actor for 3D view with color transfer function
    const ctf = vtkColorTransferFunction.newInstance();
    ctf.addRGBPoint(-1000, 0, 0, 0);
    ctf.addRGBPoint(-100, 0.4, 0.2, 0.1);
    ctf.addRGBPoint(0, 0.8, 0.6, 0.5);
    ctf.addRGBPoint(100, 0.9, 0.8, 0.7);
    ctf.addRGBPoint(400, 1, 1, 0.9);
    ctf.addRGBPoint(1000, 1, 1, 1);

    const pf = vtkPiecewiseFunction.newInstance();
    pf.addPoint(-1000, 0.0);
    pf.addPoint(-100, 0.0);
    pf.addPoint(0, 0.1);
    pf.addPoint(100, 0.3);
    pf.addPoint(400, 0.6);
    pf.addPoint(1000, 1.0);

    const volumeActor = vtkVolume.newInstance();
    const volumeMapper = vtkVolumeMapper.newInstance({ sampleDistance: 1.0 });
    
    volumeActor.setMapper(volumeMapper);
    volumeActor.getProperty().setRGBTransferFunction(0, ctf);
    volumeActor.getProperty().setScalarOpacity(0, pf);
    volumeActor.getProperty().setScalarOpacityUnitDistance(0, 3.0);
    volumeActor.getProperty().setInterpolationTypeToLinear();
    volumeActor.getProperty().setUseGradientOpacity(0, true);
    volumeActor.getProperty().setGradientOpacityMinimumValue(0, 2);
    volumeActor.getProperty().setGradientOpacityMinimumOpacity(0, 0.0);
    volumeActor.getProperty().setGradientOpacityMaximumValue(0, 20);
    volumeActor.getProperty().setGradientOpacityMaximumOpacity(0, 1.0);
    volumeActor.getProperty().setShade(true);
    volumeActor.getProperty().setAmbient(0.2);
    volumeActor.getProperty().setDiffuse(0.7);
    volumeActor.getProperty().setSpecular(0.3);
    volumeActor.getProperty().setSpecularPower(8.0);

    contextRef.current = {
      renderWindow,
      renderWindowView,
      interactor,
      renderers,
      containers,
      imageSliceActors,
      slicePlanes,
      volumeActor: { actor: volumeActor, mapper: volumeMapper },
      ctf,
      pf,
      iStyle,
      tStyle,
    };

    // Handle resize
    const resizeObserver = new ResizeObserver(resize);
    resizeObserver.observe(containerRef.current);

    return () => {
      resizeObserver.disconnect();
      window.removeEventListener("mouseup", handleGlobalMouseUp);

      if (contextRef.current) {
        containers.forEach((c) => c.element.remove());
        
        imageSliceActors.forEach(({ actor, mapper, ctf: sliceCtf }) => {
          actor.delete();
          mapper.delete();
          sliceCtf?.delete();
        });
        
        slicePlanes.forEach((p) => p.delete());
        volumeActor.delete();
        volumeMapper.delete();
        ctf.delete();
        pf.delete();
        renderers.forEach((r) => r.delete());
        interactor.delete();
        renderWindowView.delete();
        renderWindow.delete();
        contextRef.current = null;
      }
    };
  }, [bindInteractor, resize, resizeViewportContainer]);

  // --- Logic 9: Window/Level Updates ---
  useEffect(() => {
    if (!contextRef.current) return;

    const { imageSliceActors, volumeActor, ctf, pf, renderWindow } = contextRef.current;

    const low = windowLevel - windowWidth / 2;
    const high = windowLevel + windowWidth / 2;

    // 2D: strict grayscale with black background
    imageSliceActors.forEach(({ actor, ctf: sliceCtf }) => {
      actor.getProperty().setColorWindow(windowWidth);
      actor.getProperty().setColorLevel(windowLevel);

      // Anything below low stays black; anything above high stays white
      sliceCtf.removeAllPoints();
      sliceCtf.addRGBPoint(low - 1, 0, 0, 0);
      sliceCtf.addRGBPoint(low, 0, 0, 0);
      sliceCtf.addRGBPoint(high, 1, 1, 1);
      sliceCtf.addRGBPoint(high + 1, 1, 1, 1);

      actor.getProperty().setRGBTransferFunction(0, sliceCtf);
    });

    // 3D: window/level driven (keeps opacity)
    ctf.removeAllPoints();
    ctf.addRGBPoint(low - 200, 0, 0, 0);
    ctf.addRGBPoint(low, 0.4, 0.2, 0.1);
    ctf.addRGBPoint(low + (high - low) * 0.3, 0.8, 0.6, 0.5);
    ctf.addRGBPoint(low + (high - low) * 0.5, 0.9, 0.8, 0.7);
    ctf.addRGBPoint(high, 1, 1, 0.9);
    ctf.addRGBPoint(high + 200, 1, 1, 1);

    pf.removeAllPoints();
    pf.addPoint(low - 200, 0);
    pf.addPoint(low, 0);
    pf.addPoint(low + (high - low) * 0.2, opacity * 0.2);
    pf.addPoint(low + (high - low) * 0.5, opacity * 0.5);
    pf.addPoint(high, opacity);

    volumeActor.actor.getProperty().setRGBTransferFunction(0, ctf);
    volumeActor.actor.getProperty().setScalarOpacity(0, pf);

    renderWindow.render();
  }, [windowWidth, windowLevel, opacity]);

  // --- Logic 10: Data Loading ---
  useEffect(() => {
    if (!dicomData?.imageData || !contextRef.current) return;
    
    if (loadedDataRef.current === dicomData.imageData) return;
    loadedDataRef.current = dicomData.imageData;

    const { imageSliceActors, slicePlanes, volumeActor, renderers, renderWindow, ctf, pf } = contextRef.current;

    const im = dicomData.imageData;
    const bounds = im.getBounds();

    // Set slice plane origins at center of volume
    const centerX = (bounds[0] + bounds[1]) / 2;
    const centerY = (bounds[2] + bounds[3]) / 2;
    const centerZ = (bounds[4] + bounds[5]) / 2;

    slicePlanes[0].setOrigin(centerX, centerY, centerZ); // Axial
    slicePlanes[1].setOrigin(centerX, centerY, centerZ); // Coronal
    slicePlanes[2].setOrigin(centerX, centerY, centerZ); // Sagittal

    // Set input data for 2D slices
    imageSliceActors.forEach(({ mapper }) => {
      mapper.setInputData(im);
    });

    // Set input data for 3D volume
    volumeActor.mapper.setInputData(im);

    // Add volume to 3D renderer
    renderers[3].removeAllActors();
    renderers[3].removeAllVolumes();
    renderers[3].addVolume(volumeActor.actor);

    // Configure volume properties
    const dataArray = im.getPointData().getScalars();
    const dataRange = dataArray.getRange();

    volumeActor.actor.getProperty().setScalarOpacityUnitDistance(
      0,
      (vtkBoundingBox.getDiagonalLength(bounds) ?? 0) / Math.max(...im.getDimensions())
    );
    volumeActor.actor.getProperty().setGradientOpacityMinimumValue(0, 0);
    volumeActor.actor.getProperty().setGradientOpacityMaximumValue(0, (dataRange[1] - dataRange[0]) * 0.05);
    volumeActor.actor.getProperty().setRGBTransferFunction(0, ctf);
    volumeActor.actor.getProperty().setScalarOpacity(0, pf);

    // Set 3D camera
    const center = vtkBoundingBox.getCenter(bounds);
    const cam3d = renderers[3].getActiveCamera();
    cam3d.setPosition(center[0], center[1] - 500, center[2]);
    cam3d.setFocalPoint(...center);
    cam3d.setViewUp(0, 0, 1);

    // Reset cameras
    renderers.forEach((r) => r.resetCamera());
    
    renderWindow.render();
  }, [dicomData]);

  return (
    <div className="relative w-full h-full" ref={containerRef}>
      {isLoading && (
        <div className="absolute inset-0 flex items-center justify-center bg-background/80 backdrop-blur-sm z-20">
          <div className="flex flex-col items-center gap-3">
            <div className="w-10 h-10 border-4 border-primary border-t-transparent rounded-full animate-spin" />
            <span className="text-sm text-muted-foreground">Loading DICOM data...</span>
          </div>
        </div>
      )}

      {!dicomData && !isLoading && (
        <div className="absolute inset-0 flex items-center justify-center z-20">
          <div className="text-center p-8">
            <div className="text-6xl mb-4 opacity-30">🩻</div>
            <p className="text-muted-foreground">Upload DICOM files to view</p>
          </div>
        </div>
      )}
    </div>
  );
};