<template>
  <SelectedPlacedMapObjectComponent v-if="selectedPlacedMapObject" :placedMapObject="selectedPlacedMapObject" @move="moveMapObject" @rotate="rotatePlacedMapObject" @delete="deletePlacedMapObject" />
  <PlacedMapObject v-for="placedMapObject in mapEditorStore.map?.placedMapObjects" :tilemap="tilemap" :placedMapObject :selectedPlacedMapObject :movingPlacedMapObject @pointerup="clickPlacedMapObject(placedMapObject)" />
</template>

<script setup lang="ts">
import type { PlacedMapObject as PlacedMapObjectT } from '@/application/types'
import { uuidv4 } from '@/application/utilities'
import PlacedMapObject from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObject.vue'
import SelectedPlacedMapObjectComponent from '@/components/gameMaster/mapEditor/partials/SelectedPlacedMapObject.vue'
import { getTile } from '@/composables/mapComposable'
import { useMapEditorStore } from '@/stores/mapEditorStore'
import { useScene } from 'phavuer'
import { onMounted, onUnmounted, ref, watch } from 'vue'

const scene = useScene()
const mapEditorStore = useMapEditorStore()
const selectedPlacedMapObject = ref<PlacedMapObjectT | null>(null)
const movingPlacedMapObject = ref<PlacedMapObjectT | null>(null)

const props = defineProps<{
  tilemap: Phaser.Tilemaps.Tilemap
}>()

function pencil(pointer: Phaser.Input.Pointer) {
  // Check if map is set
  if (!mapEditorStore.map) return

  // Check if tool is pencil
  if (mapEditorStore.tool !== 'pencil') return

  // Check if draw mode is map_object
  if (mapEditorStore.drawMode !== 'map_object') return

  // Check if there is a selected object
  if (!mapEditorStore.selectedMapObject) return

  // Check if left mouse button is pressed
  if (!pointer.isDown) return

  // Check if shift is not pressed, this means we are moving the camera
  if (pointer.event.shiftKey) return

  // Check if alt is pressed, this means we are selecting the object
  if (pointer.event.altKey) return

  // Check if there is a tile
  const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY)
  if (!tile) return

  // Check if object already exists on position
  const existingPlacedMapObject = mapEditorStore.map.placedMapObjects.find((placedMapObject) => placedMapObject.positionX === tile.x && placedMapObject.positionY === tile.y)
  if (existingPlacedMapObject) return

  const newPlacedMapObject = {
    id: uuidv4(),
    map: mapEditorStore.map,
    mapObject: mapEditorStore.selectedMapObject,
    isRotated: false,
    positionX: tile.x,
    positionY: tile.y
  }

  // Add new object to mapObjects
  mapEditorStore.map.placedMapObjects = mapEditorStore.map.placedMapObjects.concat(newPlacedMapObject as PlacedMapObjectT)
}

function eraser(pointer: Phaser.Input.Pointer) {
  // Check if map is set
  if (!mapEditorStore.map) return

  // Check if tool is eraser
  if (mapEditorStore.tool !== 'eraser') return

  // Check if draw mode is map_object
  if (mapEditorStore.eraserMode !== 'map_object') return

  // Check if left mouse button is pressed
  if (!pointer.isDown) return

  // Check if shift is not pressed, this means we are moving the camera
  if (pointer.event.shiftKey) return

  // Check if alt is pressed, this means we are selecting the object
  if (pointer.event.altKey) return

  // Check if there is a tile
  const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY)
  if (!tile) return

  // Check if object already exists on position
  const existingPlacedMapObject = mapEditorStore.map.placedMapObjects.find((placedMapObject) => placedMapObject.positionX === tile.x && placedMapObject.positionY === tile.y)
  if (!existingPlacedMapObject) return

  // Remove existing object
  mapEditorStore.map.placedMapObjects = mapEditorStore.map.placedMapObjects.filter((placedMapObject) => placedMapObject.id !== existingPlacedMapObject.id)
}

function objectPicker(pointer: Phaser.Input.Pointer) {
  // Check if map is set
  if (!mapEditorStore.map) return

  // Check if tool is pencil
  if (mapEditorStore.tool !== 'pencil') return

  // Check if draw mode is map_object
  if (mapEditorStore.drawMode !== 'map_object') return

  // Check if left mouse button is pressed
  if (!pointer.isDown) return

  // Check if shift is not pressed, this means we are moving the camera
  if (pointer.event.shiftKey) return

  // If alt is not pressed, return
  if (!pointer.event.altKey) return

  // Check if there is a tile
  const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY)
  if (!tile) return

  // Check if object already exists on position
  const existingPlacedMapObject = mapEditorStore.map.placedMapObjects.find((placedMapObject) => placedMapObject.positionX === tile.x && placedMapObject.positionY === tile.y)
  if (!existingPlacedMapObject) return

  // Select the object
  mapEditorStore.setSelectedMapObject(existingPlacedMapObject.mapObject)
}

function moveMapObject(id: string) {
  // Check if map is set
  if (!mapEditorStore.map) return

  movingPlacedMapObject.value = mapEditorStore.map.placedMapObjects.find((object) => object.id === id) as PlacedMapObjectT

  function handlePointerMove(pointer: Phaser.Input.Pointer) {
    if (!movingPlacedMapObject.value) return

    const tile = getTile(props.tilemap, pointer.worldX, pointer.worldY)
    if (!tile) return

    movingPlacedMapObject.value.positionX = tile.x
    movingPlacedMapObject.value.positionY = tile.y
  }

  scene.input.on(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)

  function handlePointerUp() {
    scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
    movingPlacedMapObject.value = null
  }

  scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
}

function rotatePlacedMapObject(id: string) {
  // Check if map is set
  if (!mapEditorStore.map) return

  mapEditorStore.map.placedMapObjects = mapEditorStore.map.placedMapObjects.map((placedMapObject) => {
    if (placedMapObject.id === id) {
      return {
        ...placedMapObject,
        isRotated: !placedMapObject.isRotated
      }
    }
    return placedMapObject
  })
}

function deletePlacedMapObject(id: string) {
  // Check if map is set
  if (!mapEditorStore.map) return

  mapEditorStore.map.placedMapObjects = mapEditorStore.map.placedMapObjects.filter((object) => object.id !== id)
  selectedPlacedMapObject.value = null
}

function clickPlacedMapObject(placedMapObject: PlacedMapObjectT) {
  selectedPlacedMapObject.value = placedMapObject

  // If alt is pressed, select the object
  if (scene.input.activePointer.event.altKey) {
    mapEditorStore.setSelectedMapObject(placedMapObject.mapObject)
  }
}

onMounted(() => {
  scene.input.on(Phaser.Input.Events.POINTER_DOWN, pencil)
  scene.input.on(Phaser.Input.Events.POINTER_MOVE, pencil)
  scene.input.on(Phaser.Input.Events.POINTER_DOWN, eraser)
  scene.input.on(Phaser.Input.Events.POINTER_MOVE, eraser)
  scene.input.on(Phaser.Input.Events.POINTER_DOWN, objectPicker)
})

onUnmounted(() => {
  scene.input.off(Phaser.Input.Events.POINTER_DOWN, pencil)
  scene.input.off(Phaser.Input.Events.POINTER_MOVE, pencil)
  scene.input.off(Phaser.Input.Events.POINTER_DOWN, eraser)
  scene.input.off(Phaser.Input.Events.POINTER_MOVE, eraser)
  scene.input.off(Phaser.Input.Events.POINTER_DOWN, objectPicker)
})

// watch mapEditorStore.mapObjectList and update originX and originY of objects in mapObjects
watch(
  () => mapEditorStore.mapObjectList,
  (newMapObjects) => {
    if (!mapEditorStore.map) return

    const updatedMapObjects = mapEditorStore.map.placedMapObjects.map((mapObject) => {
      const updatedMapObject = newMapObjects.find((obj) => obj.id === mapObject.mapObject.id)
      if (updatedMapObject) {
        return {
          ...mapObject,
          mapObject: {
            ...mapObject.mapObject,
            originX: updatedMapObject.originX,
            originY: updatedMapObject.originY
          }
        }
      }
      return mapObject
    })

    // Update the map with the new mapObjects
    mapEditorStore.setMap({
      ...mapEditorStore.map,
      placedMapObjects: updatedMapObjects
    })

    // Update selectedMapObject if it's set
    if (mapEditorStore.selectedMapObject) {
      const updatedMapObject = newMapObjects.find((obj) => obj.id === mapEditorStore.selectedMapObject?.id)
      if (updatedMapObject) {
        mapEditorStore.setSelectedMapObject({
          ...mapEditorStore.selectedMapObject,
          originX: updatedMapObject.originX,
          originY: updatedMapObject.originY
        })
      }
    }
  }
  // { deep: true }
)
</script>
