<template>
  <SelectedZoneObject v-if="selectedZoneObject" :zoneObject="selectedZoneObject" :movingZoneObject="movingZoneObject" @move="moveZoneObject" @rotate="rotateZoneObject" @delete="deleteZoneObject" />
  <ZoneObject v-for="zoneObject in zoneEditorStore.zone?.zoneObjects" :tilemap="tilemap" :zoneObject :selectedZoneObject :movingZoneObject @pointerup="clickZoneObject(zoneObject)" />
</template>

<script setup lang="ts">
import { uuidv4 } from '@/utilities'
import { getTile } from '@/composables/zoneComposable'
import { useScene } from 'phavuer'
import { useZoneEditorStore } from '@/stores/zoneEditorStore'
import SelectedZoneObject from '@/components/gameMaster/zoneEditor/partials/SelectedZoneObject.vue'
import { onMounted, onUnmounted, ref, watch } from 'vue'
import ZoneObject from '@/components/gameMaster/zoneEditor/zonePartials/ZoneObject.vue'
import type { ZoneObject as ZoneObjectT } from '@/types'

const scene = useScene()
const zoneEditorStore = useZoneEditorStore()
const selectedZoneObject = ref<ZoneObjectT | null>(null)
const movingZoneObject = ref<ZoneObjectT | null>(null)

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

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

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

  // Check if draw mode is object
  if (zoneEditorStore.drawMode !== 'object') return

  // Check if there is a selected object
  if (!zoneEditorStore.selectedObject) 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 existingObject = zoneEditorStore.zone?.zoneObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y)
  if (existingObject) return

  const newObject = {
    id: uuidv4(),
    zoneId: zoneEditorStore.zone.id,
    zone: zoneEditorStore.zone,
    objectId: zoneEditorStore.selectedObject,
    object: zoneEditorStore.selectedObject,
    depth: 0,
    isRotated: false,
    positionX: tile.x,
    positionY: tile.y
  }

  // Add new object to zoneObjects
  zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.concat(newObject as ZoneObject)
}

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

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

  // Check if draw mode is object
  if (zoneEditorStore.eraserMode !== '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 existingObject = zoneEditorStore.zone.zoneObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y)
  if (!existingObject) return

  // Remove existing object
  zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.filter((object) => object.id !== existingObject.id)
}

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

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

  // Check if draw mode is object
  if (zoneEditorStore.drawMode !== '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 existingObject = zoneEditorStore.zone.zoneObjects.find((object) => object.positionX === tile.x && object.positionY === tile.y)
  if (!existingObject) return

  // Select the object
  zoneEditorStore.setSelectedObject(existingObject)
}

function moveZoneObject(id: string) {
  // Check if zone is set
  if (!zoneEditorStore.zone) return

  movingZoneObject.value = zoneEditorStore.zone.zoneObjects.find((object) => object.id === id) as ZoneObject

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

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

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

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

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

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

function rotateZoneObject(id: string) {
  // Check if zone is set
  if (!zoneEditorStore.zone) return

  zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.map((object) => {
    if (object.id === id) {
      return {
        ...object,
        isRotated: !object.isRotated
      }
    }
    return object
  })
}

function deleteZoneObject(id: string) {
  // Check if zone is set
  if (!zoneEditorStore.zone) return

  zoneEditorStore.zone.zoneObjects = zoneEditorStore.zone.zoneObjects.filter((object) => object.id !== id)
  selectedZoneObject.value = null
}

function clickZoneObject(zoneObject: ZoneObjectT) {
  selectedZoneObject.value = zoneObject

  // If alt is pressed, select the object
  if (scene.input.activePointer.event.altKey) {
    zoneEditorStore.setSelectedObject(zoneObject.object)
  }
}

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 zoneEditorStore.objectList and update originX and originY of objects in zoneObjects
watch(
  () => zoneEditorStore.objectList,
  (newObjects) => {
    if (!zoneEditorStore.zone) return

    const updatedZoneObjects = zoneEditorStore.zone.zoneObjects.map((zoneObject) => {
      const updatedObject = newObjects.find((obj) => obj.id === zoneObject.object.id)
      if (updatedObject) {
        return {
          ...zoneObject,
          object: {
            ...zoneObject.object,
            originX: updatedObject.originX,
            originY: updatedObject.originY
          }
        }
      }
      return zoneObject
    })

    // Update the zone with the new zoneObjects
    zoneEditorStore.setZone({
      ...zoneEditorStore.zone,
      zoneObjects: updatedZoneObjects
    })

    // Update selectedObject if it's set
    if (zoneEditorStore.selectedObject) {
      const updatedObject = newObjects.find((obj) => obj.id === zoneEditorStore.selectedObject?.id)
      if (updatedObject) {
        zoneEditorStore.setSelectedObject({
          ...zoneEditorStore.selectedObject,
          originX: updatedObject.originX,
          originY: updatedObject.originY
        })
      }
    }
  },
  { deep: true }
)
</script>
