import "@mantine/core/styles.css";
import "@mantine/notifications/styles.css";
import "./App.css";
import "./index.css";

import { CameraControls } from "@react-three/drei";
import * as THREE from "three";
import React from "react";
import { UseSceneTree } from "./SceneTree";

import { UseGui } from "./ControlPanel/GuiState";
import { UseInitialCamera } from "./InitialCameraState";
import { GetRenderRequestMessage, Message } from "./WebsocketMessages";

// Type definitions for all mutable state.
export type ViewerMutable = {
  // Function references.
  sendMessage: (message: Message) => void;
  sendCamera: (() => void) | null;
  resetCameraPose: ((animate: boolean) => void) | null;

  // DOM/Three.js references.
  canvas: HTMLCanvasElement | null;
  canvas2d: HTMLCanvasElement | null;
  scene: THREE.Scene | null;
  camera: THREE.PerspectiveCamera | null;
  backgroundMaterial: THREE.ShaderMaterial | null;
  cameraControl: CameraControls | null;

  // Scene management.
  nodeRefFromName: {
    [name: string]: undefined | THREE.Object3D;
  };

  // Message and rendering state.
  messageQueue: Message[];
  getRenderRequestState: "ready" | "triggered" | "pause" | "in_progress";
  getRenderRequest: null | GetRenderRequestMessage;

  // Interaction state.
  scenePointerInfo: {
    enabled: false | "click" | "rect-select"; // Enable box events.
    keyboard: "ctrl" | "shift" | "alt" | "meta" | null; // Keyboard modifier for pointer events.
    dragStart: [number, number]; // First mouse position.
    dragEnd: [number, number]; // Final mouse position.
    isDragging: boolean;
    isKeyDown: boolean;
  };

  // Skinned mesh state.
  skinnedMeshState: {
    [name: string]: {
      initialized: boolean;
      dirty: boolean; // Flag to track if bones need updating.
      poses: {
        wxyz: [number, number, number, number];
        position: [number, number, number];
      }[];
    };
  };

  // Global hover state tracking.
  hoveredElementsCount: number;
};

export type ViewerContextContents = {
  // Non-mutable state.
  messageSource: "websocket" | "file_playback" | "embed";

  // Zustand state hooks and actions.
  useSceneTree: UseSceneTree["store"];
  sceneTreeActions: UseSceneTree["actions"];
  useEnvironment: ReturnType<
    typeof import("./EnvironmentState").useEnvironmentState
  >;
  useGui: UseGui;
  useDevSettings: ReturnType<
    typeof import("./DevSettingsStore").useDevSettingsStore
  >;
  useInitialCamera: UseInitialCamera;

  // Single reference to all mutable state.
  mutable: React.MutableRefObject<ViewerMutable>;
};

export const ViewerContext = React.createContext<null | ViewerContextContents>(
  null,
);
