import { SocketEvent } from '@/application/enums'
import { getTile } from '@/services/mapService'
import { useGameStore } from '@/stores/gameStore'
import type { Ref } from 'vue'
import { useBaseControlsComposable } from './useBaseControlsComposable'

export function useGameControlsComposable(scene: Phaser.Scene, layer: Phaser.Tilemaps.TilemapLayer, waypoint: Ref<{ visible: boolean; x: number; y: number }>, camera: Phaser.Cameras.Scene2D.Camera) {
  const gameStore = useGameStore()
  const baseHandlers = useBaseControlsComposable(scene, layer, waypoint, camera)
  const pressedKeys = new Set<string>()

  let moveTimeout: NodeJS.Timeout | null = null
  let currentPosition = {
    x: 0,
    y: 0
  }

  // Movement constants
  const MOVEMENT_DELAY = 110 // Milliseconds between moves
  const ARROW_KEYS = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'] as const

  function updateCurrentPosition() {
    if (!gameStore.character) return
    currentPosition = {
      x: gameStore.character.positionX,
      y: gameStore.character.positionY
    }
  }

  function calculateNewPosition() {
    let newX = currentPosition.x
    let newY = currentPosition.y

    if (pressedKeys.has('ArrowLeft')) newX--
    if (pressedKeys.has('ArrowRight')) newX++
    if (pressedKeys.has('ArrowUp')) newY--
    if (pressedKeys.has('ArrowDown')) newY++

    return { newX, newY }
  }

  function emitMovement(x: number, y: number) {
    if (x === currentPosition.x && y === currentPosition.y) return

    gameStore.connection?.emit(SocketEvent.MAP_CHARACTER_MOVE, {
      positionX: x,
      positionY: y
    })

    currentPosition = { x, y }
  }

  function startMovementLoop() {
    if (moveTimeout) return

    const move = () => {
      if (pressedKeys.size === 0) {
        stopMovementLoop()
        return
      }

      updateCurrentPosition()
      const { newX, newY } = calculateNewPosition()
      emitMovement(newX, newY)

      moveTimeout = setTimeout(move, MOVEMENT_DELAY)
    }

    move()
  }

  function stopMovementLoop() {
    if (moveTimeout) {
      clearTimeout(moveTimeout)
      moveTimeout = null
    }
  }

  // Pointer Handlers
  function handlePointerDown(pointer: Phaser.Input.Pointer) {
    baseHandlers.startDragging(pointer)
  }

  function handlePointerMove(pointer: Phaser.Input.Pointer) {
    baseHandlers.updateWaypoint(pointer.worldX, pointer.worldY)
    baseHandlers.handleDragMap(pointer)
  }

  function handlePointerUp(pointer: Phaser.Input.Pointer) {
    baseHandlers.stopDragging()

    const pointerTile = getTile(layer, pointer.worldX, pointer.worldY)
    if (!pointerTile) return

    emitMovement(pointerTile.x, pointerTile.y)
  }

  // Keyboard Handlers
  function handleKeyDown(event: KeyboardEvent) {
    if (!gameStore.character) return

    if (ARROW_KEYS.includes(event.key as (typeof ARROW_KEYS)[number])) {
      if (event.repeat) return

      pressedKeys.add(event.key)
      updateCurrentPosition()
      startMovementLoop()
    }

    if (event.key === 'Control') {
      gameStore.connection?.emit(SocketEvent.MAP_CHARACTER_ATTACK)
    }
  }

  function handleKeyUp(event: KeyboardEvent) {
    pressedKeys.delete(event.key)

    if (pressedKeys.size === 0) {
      stopMovementLoop()
    }
  }

  const setupControls = () => {
    updateCurrentPosition() // Initialize position

    scene.input.on(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
    scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
    scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
    scene.input.on(Phaser.Input.Events.POINTER_WHEEL, baseHandlers.handleZoom)
    scene.input.keyboard!.on('keydown', handleKeyDown)
    scene.input.keyboard!.on('keyup', handleKeyUp)
  }

  const cleanupControls = () => {
    stopMovementLoop()
    pressedKeys.clear()

    scene.input.off(Phaser.Input.Events.POINTER_DOWN, handlePointerDown)
    scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
    scene.input.off(Phaser.Input.Events.POINTER_UP, handlePointerUp)
    scene.input.off(Phaser.Input.Events.POINTER_WHEEL, baseHandlers.handleZoom)
    scene.input.keyboard!.off('keydown', handleKeyDown)
    scene.input.keyboard!.off('keyup', handleKeyUp)
  }

  return { setupControls, cleanupControls }
}