<template>
  <div class="h-full" v-if="!selectedGroup">
    <div class="grid grid-cols-4 gap-2 justify-items-center">
      <div v-for="group in groupedTiles" :key="group.parent.id" class="flex flex-col items-center justify-center relative">
        <img
          class="max-w-full max-h-full border-2 border-solid rounded cursor-pointer transition-all duration-300"
          :src="`${config.server_endpoint}/textures/tiles/${group.parent.id}.png`"
          :alt="group.parent.name"
          @click="openGroup(group)"
          @load="() => tileProcessor.processTile(group.parent)"
          :class="{
            'border-cyan shadow-lg': isActiveTile(group.parent),
            'border-transparent hover:border-gray-300': !isActiveTile(group.parent)
          }"
        />
        <span class="text-xs mt-1">{{ getTileCategory(group.parent) }}</span>
        <span v-if="group.children.length > 0" class="absolute top-0 right-0 bg-cyan text-white rounded-full w-5 h-5 flex items-center justify-center text-xs">
          {{ group.children.length + 1 }}
        </span>
      </div>
    </div>
  </div>
  <div v-else class="h-full overflow-auto">
    <div class="p-4">
      <button @click="closeGroup" class="btn-cyan mb-4">Back to All Tiles</button>
      <h4 class="text-lg mb-4">{{ selectedGroup.parent.name }} Group</h4>
      <div class="grid grid-cols-4 gap-2 justify-items-center">
        <div class="flex flex-col items-center justify-center">
          <img
            class="max-w-full max-h-full border-2 border-solid rounded cursor-pointer transition-all duration-300"
            :src="`${config.server_endpoint}/textures/tiles/${selectedGroup.parent.id}.png`"
            :alt="selectedGroup.parent.name"
            @click="selectTile(selectedGroup.parent.id)"
            :class="{
              'border-cyan shadow-lg': isActiveTile(selectedGroup.parent),
              'border-transparent hover:border-gray-300': !isActiveTile(selectedGroup.parent)
            }"
          />
          <span class="text-xs mt-1">{{ getTileCategory(selectedGroup.parent) }}</span>
        </div>
        <div v-for="childTile in selectedGroup.children" :key="childTile.id" class="flex flex-col items-center justify-center">
          <img
            class="max-w-full max-h-full border-2 border-solid rounded cursor-pointer transition-all duration-300"
            :src="`${config.server_endpoint}/textures/tiles/${childTile.id}.png`"
            :alt="childTile.name"
            @click="selectTile(childTile.id)"
            :class="{
              'border-cyan shadow-lg': isActiveTile(childTile),
              'border-transparent hover:border-gray-300': !isActiveTile(childTile)
            }"
          />
          <span class="text-xs mt-1">{{ getTileCategory(childTile) }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import config from '@/application/config'
import type { Tile } from '@/application/types'
import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
import { useTileProcessingComposable } from '@/composables/useTileProcessingComposable'
import { TileStorage } from '@/storage/storages'
import { computed, onMounted, onUnmounted, ref } from 'vue'

const isOpen = ref(false)
const tileStorage = new TileStorage()
const mapEditor = useMapEditorComposable()
const tileProcessor = useTileProcessingComposable()
const searchQuery = ref('')
const selectedTags = ref<string[]>([])
const tileCategories = ref<Map<string, string>>(new Map())
const selectedGroup = ref<{ parent: Tile; children: Tile[] } | null>(null)
const tiles = ref<Tile[]>([])

defineExpose({
  open: () => (isOpen.value = true),
  close: () => (isOpen.value = false),
  toggle: () => (isOpen.value = !isOpen.value)
})

const uniqueTags = computed(() => {
  const allTags = tiles.value.flatMap((tile) => tile.tags || [])
  return Array.from(new Set(allTags))
})

const groupedTiles = computed(() => {
  const groups: { parent: Tile; children: Tile[] }[] = []
  const filteredTiles = tiles.value.filter((tile) => {
    const matchesSearch = !searchQuery.value || tile.name.toLowerCase().includes(searchQuery.value.toLowerCase())
    const matchesTags = selectedTags.value.length === 0 || (tile.tags && selectedTags.value.some((tag) => tile.tags.includes(tag)))
    return matchesSearch && matchesTags
  })

  filteredTiles.forEach((tile) => {
    const parentGroup = groups.find((group) => tileProcessor.areTilesRelated(group.parent, tile))
    if (parentGroup && parentGroup.parent.id !== tile.id) {
      parentGroup.children.push(tile)
    } else {
      groups.push({ parent: tile, children: [] })
    }
  })

  return groups
})

const toggleTag = (tag: string) => {
  if (selectedTags.value.includes(tag)) {
    selectedTags.value = selectedTags.value.filter((t) => t !== tag)
  } else {
    selectedTags.value.push(tag)
  }
}

function getTileCategory(tile: Tile): string {
  return tileCategories.value.get(tile.id) || ''
}

function openGroup(group: { parent: Tile; children: Tile[] }) {
  selectedGroup.value = group
}

function closeGroup() {
  selectedGroup.value = null
}

function selectTile(tile: string) {
  mapEditor.setSelectedTile(tile)
}

function isActiveTile(tile: Tile): boolean {
  return mapEditor.selectedTile.value === tile.id
}

onMounted(async () => {
  tiles.value = await tileStorage.getAll()
  const initialBatchSize = 20
  const initialTiles = tiles.value.slice(0, initialBatchSize)
  initialTiles.forEach((tile) => tileProcessor.processTile(tile))

  // Process remaining tiles in background
  setTimeout(() => {
    tiles.value.slice(initialBatchSize).forEach((tile) => tileProcessor.processTile(tile))
  }, 1000)
})

onUnmounted(() => {
  tileProcessor.cleanup()
})
</script>
