"use client"
import { Canvas, useFrame } from '@react-three/fiber'
import { Sphere, Line } from '@react-three/drei'
import * as THREE from 'three'
import { Leva, useControls, button } from 'leva'
import { StrictMode, useRef, useEffect, memo } from 'react'

// Import our new modular architecture
import { useDrawingState, useSnapToGrid, useCoordinateTransform, useCursorIndicator, useKeyboardEvents } from './hooks.js'
import { DrawableObject } from './DrawableObjects.jsx'
import { ToolPreview } from './ToolPreview.jsx'

export default function App() {
  return (
    <StrictMode>
      <Leva flat />
      <Canvas orthographic camera={{ zoom: 50, near: 0.1, far: 200, position: [0, 0, 15] }}>
        <Experience />
      </Canvas>
    </StrictMode>
  )
}

export function Experience() {
  // Use our custom hooks for state management
  const {
    drawnObjects,
    currentTool,
    isDrawing,
    drawingState,
    cursorPosition,
    handleToolChange,
    handleCanvasClick,
    handleMouseMove,
    handleKeyPress,
    handleObjectDelete,
    clearAll,
    toolOptions,
    toolSpecificData
  } = useDrawingState()

  const { snapEnabled, snapValue, setSnapEnabled, setSnapValue } = useSnapToGrid(0.5)
  const { transformPoint } = useCoordinateTransform()

  // Leva controls
  const { tool, snap, snapVal, showLengths } = useControls('Drawing Tools (Refactored)', {
    tool: {
      value: 'line',
      options: toolOptions,
      onChange: handleToolChange
    },
    snap: {
      value: true,
      onChange: setSnapEnabled
    },
    snapVal: {
      value: 0.5,
      min: 0.1,
      max: 2,
      step: 0.1,
      onChange: setSnapValue
    },
    showLengths: false,
    clear: button(clearAll)
  })

  // Set up keyboard event handling
  useKeyboardEvents(handleKeyPress)

  return (
    <>
      <directionalLight position={[1, 2, 3]} intensity={1.5} />
      <ambientLight intensity={0.5} />

      <DrawingCanvas
        onCanvasClick={handleCanvasClick}
        onMouseMove={handleMouseMove}
        snapEnabled={snapEnabled}
        snapValue={snapValue}
        transformPoint={transformPoint}
      />

      {/* Render completed objects */}
      {drawnObjects.map(obj => (
        <DrawableObject
          key={obj.id}
          object={obj}
          isDeleteMode={currentTool === 'delete'}
          showLengths={showLengths}
          onDelete={() => handleObjectDelete(obj.id)}
        />
      ))}

      {/* Render current drawing preview */}
      {isDrawing && drawingState && (
        <ToolPreview
          tool={currentTool}
          state={drawingState}
          cursorPosition={cursorPosition}
          showLengths={showLengths}
          onShapeComplete={() => handleKeyPress('Escape')}
        />
      )}

      <GridHelper snapValue={snapValue} visible={snapEnabled} />
    </>
  )
}

// Drawing canvas component
export function DrawingCanvas({ onCanvasClick, onMouseMove, snapEnabled, snapValue, transformPoint }) {
  const { cursorRef, showCursor, hideCursor } = useCursorIndicator()
  const planeRef = useRef()

  return (
    <mesh
      ref={planeRef}
      position={[0, 0, 0]}
      onPointerMove={(e) => {
        if (!planeRef.current) return
        const localPoint = planeRef.current.worldToLocal(e.point.clone())
        const transformedPoint = transformPoint(localPoint, snapEnabled, snapValue)

        showCursor(transformedPoint)
        onMouseMove(transformedPoint, snapEnabled, snapValue)
      }}
      onPointerOut={hideCursor}
      onClick={(e) => {
        if (!planeRef.current) return
        const localPoint = planeRef.current.worldToLocal(e.point.clone())
        const transformedPoint = transformPoint(localPoint, snapEnabled, snapValue)
        onCanvasClick(transformedPoint, snapEnabled, snapValue)
      }}
    >
      <planeGeometry args={[20, 20]} />
      <meshBasicMaterial transparent opacity={0.1} color="lightblue" />

      <CursorIndicator ref={cursorRef} />
    </mesh>
  )
}

// Cursor indicator component
export const CursorIndicator = ({ color = "orange", size = 0.1, ...props }) => {
  const ref = useRef()

  useFrame(() => {
    if (ref.current) {
      ref.current.rotation.x += 0.01
      ref.current.rotation.y += 0.01
    }
  })

  return (
    <mesh ref={ref} raycast={() => null} visible={false} {...props}>
      <sphereGeometry args={[size]} />
      <meshBasicMaterial color={color} />
    </mesh>
  )
}

// Grid helper component with React.memo to prevent unnecessary re-renders
export const GridHelper = memo(function GridHelper({ snapValue, visible }) {
  if (!visible) return null
  
  const lines = []
  const size = 20
  const divisions = size / snapValue
  
  for (let i = -divisions; i <= divisions; i++) {
    const pos = i * snapValue
    lines.push(
      <Line 
        key={`h${i}`}
        points={[[-size/2, pos, 0], [size/2, pos, 0]]}
        color="gray"
        lineWidth={0.5}
      />,
      <Line 
        key={`v${i}`}
        points={[[pos, -size/2, 0], [pos, size/2, 0]]}
        color="gray"
        lineWidth={0.5}
      />
    )
  }
  
  return <group>{lines}</group>
})

Comments (0)

Loading comments...