import { useEffect, useRef, useState, useCallback } from 'react'
import * as THREE from 'three'
import { useI18n } from '../../i18n/useI18n'

interface AngleEditorProps {
  horizontal: number    // 0-360
  vertical: number      // -30 to 30
  zoom: number          // 0.8 to 1.5
  onChange: (h: number, v: number, z: number) => void
}

export function AngleEditor({ horizontal, vertical, zoom, onChange }: AngleEditorProps) {
  const { t } = useI18n()
  const containerRef = useRef<HTMLDivElement>(null)
  const rendererRef = useRef<THREE.WebGLRenderer | null>(null)
  const sceneRef = useRef<THREE.Scene | null>(null)
  const cameraRef = useRef<THREE.PerspectiveCamera | null>(null)
  const dotRef = useRef<THREE.Mesh | null>(null)
  const isDraggingRef = useRef(false)
  const animFrameRef = useRef<number>(0)

  const [localH, setLocalH] = useState(horizontal)
  const [localV, setLocalV] = useState(vertical)
  const [localZ, setLocalZ] = useState(zoom)

  // Sync external changes
  useEffect(() => {
    setLocalH(horizontal)
    setLocalV(vertical)
    setLocalZ(zoom)
  }, [horizontal, vertical, zoom])

  const updateDotPosition = useCallback((h: number, v: number) => {
    if (!dotRef.current) return
    const radius = 1.05
    const hRad = (h * Math.PI) / 180
    const vRad = (v * Math.PI) / 180
    dotRef.current.position.set(
      radius * Math.cos(vRad) * Math.sin(hRad),
      radius * Math.sin(vRad),
      radius * Math.cos(vRad) * Math.cos(hRad)
    )
  }, [])

  // Initialize Three.js scene
  useEffect(() => {
    const container = containerRef.current
    if (!container) return

    const width = container.clientWidth
    const height = 220

    // Scene
    const scene = new THREE.Scene()
    scene.background = new THREE.Color(0x181b24)
    sceneRef.current = scene

    // Camera
    const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 100)
    camera.position.set(0, 1.2, 3.2)
    camera.lookAt(0, 0, 0)
    cameraRef.current = camera

    // Renderer
    const renderer = new THREE.WebGLRenderer({ antialias: true })
    renderer.setSize(width, height)
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
    container.appendChild(renderer.domElement)
    rendererRef.current = renderer

    // Sphere wireframe (subject)
    const sphereGeom = new THREE.SphereGeometry(1, 24, 16)
    const wireframe = new THREE.WireframeGeometry(sphereGeom)
    const lineMat = new THREE.LineBasicMaterial({ color: 0x3a3f52, transparent: true, opacity: 0.5 })
    const sphereLines = new THREE.LineSegments(wireframe, lineMat)
    scene.add(sphereLines)

    // Equator ring for horizontal reference
    const ringGeom = new THREE.RingGeometry(1.0, 1.02, 64)
    const ringMat = new THREE.MeshBasicMaterial({ color: 0x5c6070, side: THREE.DoubleSide })
    const ring = new THREE.Mesh(ringGeom, ringMat)
    ring.rotation.x = -Math.PI / 2
    scene.add(ring)

    // Camera dot (draggable)
    const dotGeom = new THREE.SphereGeometry(0.08, 16, 16)
    const dotMat = new THREE.MeshBasicMaterial({ color: 0x6386ff })
    const dot = new THREE.Mesh(dotGeom, dotMat)
    scene.add(dot)
    dotRef.current = dot

    // Update initial dot position
    updateDotPosition(localH, localV)

    // Axis helpers
    // X axis (red, subtle)
    const xLine = new THREE.BufferGeometry().setFromPoints([
      new THREE.Vector3(-1.5, 0, 0),
      new THREE.Vector3(1.5, 0, 0),
    ])
    scene.add(new THREE.Line(xLine, new THREE.LineBasicMaterial({ color: 0x5c2020, transparent: true, opacity: 0.3 })))

    // Z axis (blue, subtle)
    const zLine = new THREE.BufferGeometry().setFromPoints([
      new THREE.Vector3(0, 0, -1.5),
      new THREE.Vector3(0, 0, 1.5),
    ])
    scene.add(new THREE.Line(zLine, new THREE.LineBasicMaterial({ color: 0x20205c, transparent: true, opacity: 0.3 })))

    // Line from center to dot
    const lineGeom = new THREE.BufferGeometry().setFromPoints([
      new THREE.Vector3(0, 0, 0),
      dot.position.clone(),
    ])
    const lineDash = new THREE.LineBasicMaterial({ color: 0x6386ff, transparent: true, opacity: 0.4 })
    const centerLine = new THREE.Line(lineGeom, lineDash)
    scene.add(centerLine)

    // Animation loop
    const animate = () => {
      animFrameRef.current = requestAnimationFrame(animate)
      // Update center line endpoint
      const positions = centerLine.geometry.attributes.position
      if (positions && dotRef.current) {
        (positions as THREE.BufferAttribute).setXYZ(1, dotRef.current.position.x, dotRef.current.position.y, dotRef.current.position.z)
        positions.needsUpdate = true
      }
      renderer.render(scene, camera)
    }
    animate()

    // Mouse drag handling
    const raycaster = new THREE.Raycaster()
    const mouse = new THREE.Vector2()

    const getMousePos = (e: MouseEvent) => {
      const rect = renderer.domElement.getBoundingClientRect()
      mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1
      mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1
      return mouse
    }

    const handleMouseDown = (e: MouseEvent) => {
      const m = getMousePos(e)
      raycaster.setFromCamera(m, camera)
      const intersects = raycaster.intersectObject(dot)
      if (intersects.length > 0) {
        isDraggingRef.current = true
        renderer.domElement.style.cursor = 'grabbing'
        e.preventDefault()
      }
    }

    const handleMouseMove = (e: MouseEvent) => {
      if (!isDraggingRef.current) {
        // Hover effect
        const m = getMousePos(e)
        raycaster.setFromCamera(m, camera)
        const intersects = raycaster.intersectObject(dot)
        renderer.domElement.style.cursor = intersects.length > 0 ? 'grab' : 'default'
        return
      }

      const m = getMousePos(e)
      raycaster.setFromCamera(m, camera)

      // Intersect with sphere
      const sphereTarget = new THREE.Sphere(new THREE.Vector3(0, 0, 0), 1.05)
      const ray = raycaster.ray
      const intersection = new THREE.Vector3()
      const hit = ray.intersectSphere(sphereTarget, intersection)

      if (hit) {
        // Convert position to h/v angles
        const h = (Math.atan2(intersection.x, intersection.z) * 180) / Math.PI
        const v = Math.asin(Math.max(-1, Math.min(1, intersection.y / 1.05))) * 180 / Math.PI
        const clampedH = ((h % 360) + 360) % 360
        const clampedV = Math.max(-30, Math.min(30, v))

        setLocalH(Math.round(clampedH))
        setLocalV(Math.round(clampedV))
        updateDotPosition(clampedH, clampedV)
      }
    }

    const handleMouseUp = () => {
      if (isDraggingRef.current) {
        isDraggingRef.current = false
        renderer.domElement.style.cursor = 'default'
      }
    }

    renderer.domElement.addEventListener('mousedown', handleMouseDown)
    window.addEventListener('mousemove', handleMouseMove)
    window.addEventListener('mouseup', handleMouseUp)

    // Handle resize
    const handleResize = () => {
      const w = container.clientWidth
      camera.aspect = w / height
      camera.updateProjectionMatrix()
      renderer.setSize(w, height)
    }
    window.addEventListener('resize', handleResize)

    return () => {
      cancelAnimationFrame(animFrameRef.current)
      renderer.domElement.removeEventListener('mousedown', handleMouseDown)
      window.removeEventListener('mousemove', handleMouseMove)
      window.removeEventListener('mouseup', handleMouseUp)
      window.removeEventListener('resize', handleResize)
      renderer.dispose()
      if (container.contains(renderer.domElement)) {
        container.removeChild(renderer.domElement)
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  // Update dot when sliders change
  useEffect(() => {
    updateDotPosition(localH, localV)
  }, [localH, localV, updateDotPosition])

  // Propagate changes
  useEffect(() => {
    onChange(localH, localV, localZ)
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [localH, localV, localZ])

  return (
    <div>
      {/* Three.js canvas */}
      <div
        ref={containerRef}
        style={{
          width: '100%',
          height: '220px',
          borderRadius: 'var(--radius-sm)',
          overflow: 'hidden',
          border: '1px solid var(--border)',
          marginBottom: '16px',
        }}
      />

      {/* Value display */}
      <div style={{
        display: 'flex',
        gap: '12px',
        marginBottom: '12px',
        justifyContent: 'center',
      }}>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: '12px', color: 'var(--accent)' }}>
          H: {localH}°
        </span>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: '12px', color: 'var(--accent)' }}>
          V: {localV}°
        </span>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: '12px', color: 'var(--accent)' }}>
          Z: {localZ.toFixed(1)}x
        </span>
      </div>

      {/* Sliders */}
      <div style={{ display: 'grid', gap: '10px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
          <label style={{ fontSize: '12px', fontWeight: 600, color: 'var(--text-muted)', minWidth: '36px' }}>
            {t('angle.horizontal')}
          </label>
          <input
            type="range"
            min={0}
            max={360}
            value={localH}
            onChange={(e) => setLocalH(Number(e.target.value))}
            style={{ flex: 1, padding: 0, background: 'transparent', border: 'none', boxShadow: 'none' }}
          />
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: '11px', color: 'var(--text-dim)', minWidth: '32px', textAlign: 'right' }}>
            {localH}°
          </span>
        </div>

        <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
          <label style={{ fontSize: '12px', fontWeight: 600, color: 'var(--text-muted)', minWidth: '36px' }}>
            {t('angle.vertical')}
          </label>
          <input
            type="range"
            min={-30}
            max={30}
            value={localV}
            onChange={(e) => setLocalV(Number(e.target.value))}
            style={{ flex: 1, padding: 0, background: 'transparent', border: 'none', boxShadow: 'none' }}
          />
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: '11px', color: 'var(--text-dim)', minWidth: '32px', textAlign: 'right' }}>
            {localV}°
          </span>
        </div>

        <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
          <label style={{ fontSize: '12px', fontWeight: 600, color: 'var(--text-muted)', minWidth: '36px' }}>
            {t('angle.zoom')}
          </label>
          <input
            type="range"
            min={80}
            max={150}
            value={Math.round(localZ * 100)}
            onChange={(e) => setLocalZ(Number(e.target.value) / 100)}
            style={{ flex: 1, padding: 0, background: 'transparent', border: 'none', boxShadow: 'none' }}
          />
          <span style={{ fontFamily: 'var(--font-mono)', fontSize: '11px', color: 'var(--text-dim)', minWidth: '32px', textAlign: 'right' }}>
            {localZ.toFixed(1)}x
          </span>
        </div>
      </div>
    </div>
  )
}
