<template>
  <MapTiles v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer />
  <PlacedMapObjects v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer />
  <Characters v-if="tileMap && mapStore.characters" :tileMap />
</template>

<script setup lang="ts">
import type { MapCharacter, mapLoadData, UUID } from '@/application/types'
import { unduplicateArray } from '@/application/utilities'
import Characters from '@/components/game/map/Characters.vue'
import MapTiles from '@/components/game/map/MapTiles.vue'
import PlacedMapObjects from '@/components/game/map/PlacedMapObjects.vue'
import { createTileLayer, createTileMap, loadTileTexturesFromMapTileArray } from '@/services/mapService'
import { MapStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore'
import { useMapStore } from '@/stores/mapStore'
import { useScene } from 'phavuer'
import { onUnmounted, shallowRef, watch } from 'vue'

const scene = useScene()

const gameStore = useGameStore()
const mapStore = useMapStore()

const mapStorage = new MapStorage()

const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
const tileMapLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>()

// Event listeners
gameStore.connection?.on('map:character:teleport', async (data: mapLoadData) => {
  mapStore.setMapId(data.mapId)
  mapStore.setCharacters(data.characters)
})

gameStore.connection?.on('map:character:join', async (data: MapCharacter) => {
  mapStore.addCharacter(data)
})

gameStore.connection?.on('map:character:leave', (characterId: UUID) => {
  mapStore.removeCharacter(characterId)
})

gameStore.connection?.on('map:character:attack', (characterId: UUID) => {
  mapStore.updateCharacterProperty(characterId, 'isAttacking', true)
})

gameStore.connection?.on('map:character:move', (data: { characterId: UUID; positionX: number; positionY: number; rotation: number; isMoving: boolean }) => {
  mapStore.updateCharacterPosition(data)
  // @TODO: Replace with universal class, composable or store
  if (data.characterId === gameStore.character?.id) {
    gameStore.character!.positionX = data.positionX
    gameStore.character!.positionY = data.positionY
    gameStore.character!.rotation = data.rotation
  }
})

async function initialize() {
  if (!mapStore.mapId) return

  const map = await mapStorage.get(mapStore.mapId)
  if (!map) return

  await loadTileTexturesFromMapTileArray(mapStore.mapId, scene)

  tileMap.value = createTileMap(scene, map)
  tileMapLayer.value = createTileLayer(tileMap.value, unduplicateArray(map.tiles.flat()))
}

watch(
  () => mapStore.mapId,
  async () => {
    await initialize()
  }
)

onUnmounted(() => {
  if (tileMap.value) {
    tileMap.value.destroyLayer('tiles')
    tileMap.value.removeAllLayers()
    tileMap.value.destroy()
  }

  mapStore.reset()
  gameStore.connection?.off('map:character:teleport')
  gameStore.connection?.off('map:character:join')
  gameStore.connection?.off('map:character:leave')
  gameStore.connection?.off('map:character:move')
})
</script>
