<template>
  <div class="relative max-lg:h-dvh flex flex-row-reverse">
    <div class="lg:bg-gradient-to-l bg-gradient-to-b from-gray-900 to-transparent w-full lg:w-1/2 h-[65dvh] lg:h-dvh absolute left-0 max-lg:bottom-0 lg:top-0 z-10"></div>
    <div class="bg-[url('/assets/login/login-bg.png')] opacity-20 w-full lg:w-1/2 h-[65dvh] lg:h-dvh absolute left-0 max-lg:bottom-0 lg:top-0 bg-no-repeat bg-cover bg-center grayscale"></div>
    <div class="bg-gray-900 z-20 w-full lg:w-1/2 h-[35dvh] lg:h-dvh relative"></div>
    <div class="max-lg:hidden absolute top-8 right-0 py-[18px] pr-[15px] pl-32 bg-gradient-to-r from-transparent to-cyan-900 z-20">
      <h2 class="text-white">CHARACTER SELECTION</h2>
    </div>
    <div class="ui-wrapper h-dvh w-[calc(100%_-_80px)] sm:w-[calc(100%_-_160px)] absolute flex flex-col justify-center items-center gap-8 lg:gap-14 px-10 sm:px-20 z-30">
      <div class="filler"></div>
      <div class="w-2/3 max-w-[860px]" v-if="!isLoading">
        <div class="mb-5 flex flex-col gap-1">
          <h1 class="text-white font-bold">{{ isCreatingCharacter ? 'CREATE CHARACTER' : 'SELECT CHARACTER TO PLAY' }}</h1>
          <p class="m-0" v-if="!isCreatingCharacter">Maximum of 4 characters can be created per player</p>
          <p class="m-0" v-if="isCreatingCharacter">Customize your new character</p>
        </div>
        <div class="flex w-full max-lg:flex-col lg:h-[400px] default-border rounded-md bg-gray">
          <div class="lg:min-w-[285px] max-lg:min-h-[383px] lg:w-1/3 h-full bg-[url('/assets/ui-texture.png')] bg-no-repeat bg-cover bg-center border-0 max-lg:border-b lg:border-r border-solid border-gray-500 max-lg:rounded-t-md lg:rounded-l-md relative">
            <div class="absolute right-[calc(100%_+_16px)] -top-px flex gap-2 flex-col">
              <div v-for="character in characters" :key="character.id" class="character relative rounded default-border w-12 h-12 bg-[url('/assets/ui-texture.png')] after:absolute after:w-full after:h-px after:bg-gray-500" :class="{ active: selectedCharacterId === character.id }">
                <img src="/assets/placeholders/head.png" class="w-9 h-9 object-contain center-element" alt="Player head" />
                <input class="h-full w-full absolute m-0 z-10 hover:cursor-pointer focus-visible:outline-offset-0 btn-sound" type="radio" name="character" :value="character.id" v-model="selectedCharacterId" />
              </div>
              <div class="character relative rounded default-border w-12 h-12 bg-[url('/assets/ui-texture.png')]" :class="{ active: isCreatingCharacter }" v-if="characters.length < characterCreationSettings.maxCharacters">
                <button class="p-0 h-full w-full flex flex-col justify-between focus-visible:outline-offset-0 btn-sound" @click="startCharacterCreation">
                  <img class="w-6 h-6 object-contain center-element btn-sound" draggable="false" src="/assets/icons/plus-icon.svg" alt="Add character" />
                </button>
              </div>
            </div>
            <div class="py-6 px-8 h-[calc(100%_-_48px)] flex flex-col items-center gap-6 justify-center">
              <template v-if="selectedCharacterId && !isCreatingCharacter">
                <input class="input-field w-[158px]" type="text" name="name" :placeholder="characters.find((c) => c.id == selectedCharacterId)?.name" v-model="newNickname" />
                <div class="flex flex-col gap-4 items-center">
                  <div class="flex flex-col gap-3">
                    <div class="bg-[url('/assets/ui-elements/character-select-ui-shape.svg')] w-[190px] h-52 bg-no-repeat bg-center flex items-center justify-between">
                      <button class="ml-6 w-4 h-8 p-0">
                        <img src="/assets/icons/triangle-icon.svg" class="w-3 h-3.5 m-auto" alt="Arrow left" />
                      </button>
                      <img class="w-24 object-contain mb-3.5 max-h-[70%]" alt="Player avatar" :src="config.server_endpoint + '/avatar/s/' + characters.find((c) => c.id === selectedCharacterId)?.characterType + '/' + (selectedHairId ?? 'default')" />
                      <button class="mr-6 w-4 h-8 p-0">
                        <img src="/assets/icons/triangle-icon.svg" class="w-3 h-3.5 -scale-x-100" alt="Arrow right" />
                      </button>
                    </div>
                  </div>
                </div>
              </template>
              <template v-if="isCreatingCharacter">
                <div class="flex flex-col gap-4 items-center">
                  <input class="input-field" v-model="newCharacterName" name="name" id="name" placeholder="Enter a nickname..." />
                  <div class="bg-[url('/assets/ui-elements/character-select-ui-shape.svg')] w-[190px] h-52 bg-no-repeat bg-center flex items-center justify-center">
                    <button class="ml-6 w-4 h-8 p-0">
                      <img src="/assets/icons/triangle-icon.svg" class="w-3 h-3.5 m-auto" alt="Arrow left" />
                    </button>
                    <img class="w-24 object-contain mb-3.5 max-h-[70%]" alt="Player avatar" :src="config.server_endpoint + '/avatar/s/' + defaultCharacterTypeId + '/' + (selectedHairId ?? 'default')" />
                    <button class="mr-6 w-4 h-8 p-0">
                      <img src="/assets/icons/triangle-icon.svg" class="w-3 h-3.5 -scale-x-100" alt="Arrow right" />
                    </button>
                  </div>
                  <div class="flex justify-between w-[190px]">
                    <button class="btn-empty flex gap-2" :class="{ selected: selectedGender === 'MALE' }" @click="selectedGender = 'MALE'">
                      <img src="/assets/icons/male-icon.svg" class="w-4 h-4 m-auto" alt="Male symbol" />
                      <span class="text-white">Male</span>
                    </button>
                    <button class="btn-empty flex gap-2" :class="{ selected: selectedGender === 'FEMALE' }" @click="selectedGender = 'FEMALE'">
                      <img src="/assets/icons/male-icon.svg" class="w-4 h-4 m-auto" alt="Female symbol" />
                      <span class="text-white">Female</span>
                    </button>
                  </div>
                </div>
              </template>
            </div>
          </div>
          <div class="flex-1 lg:w-2/3 max-lg:min-h-[212px] h-full bg-[url('/assets/ui-texture.png')] bg-no-repeat bg-cover bg-center max-lg:rounded-bl-md rounded-r-md">
            <div class="py-6 px-8 h-[calc(100%_-_48px)] flex flex-col items-center gap-10" v-if="selectedCharacterId || isCreatingCharacter">
              <div class="flex flex-col gap-3 w-full">
                <span class="text-sm">Hair color</span>
                <div class="flex gap-2 flex-wrap">
                  <div
                    class="hair-deselect relative flex justify-center items-center bg-gray default-border w-[18px] h-[18px] p-2 rounded-sm hover:bg-gray-500 hover:border-gray-400 focus-visible:outline-none focus-visible:border-white focus-visible:bg-cyan has-[:checked]:bg-cyan has-[:checked]:border-transparent"
                  >
                    <img src="/assets/icons/x-button-gray.svg" class="w-4 h-4" alt="Empty button" />
                    <input type="radio" name="hair-color" :value="null" v-model="selectedHairColor" class="h-full w-full absolute left-0 top-0 m-0 z-10 hover:cursor-pointer focus-visible:outline-offset-0 focus-visible:outline-white" />
                  </div>
                  <div
                    v-for="color in uniqueHairColors"
                    class="relative flex justify-center items-center default-border w-[18px] h-[18px] p-2 rounded-sm hover:bg-gray-500 hover:border-gray-400 focus-visible:outline-none focus-visible:border-gray-300 focus-visible:bg-gray-500 has-[:checked]:bg-cyan has-[:checked]:border-transparent"
                  >
                    <div class="w-full h-full rounded-sm" :style="getHairColorStyle(color)"></div>
                    <input type="radio" name="hair-color" :value="color" v-model="selectedHairColor" class="h-full w-full absolute left-0 top-0 m-0 z-10 hover:cursor-pointer focus-visible:outline-offset-0 focus-visible:outline-white" />
                  </div>
                </div>
              </div>
              <div class="flex flex-col gap-3 w-full">
                <span class="text-sm">Hairstyle</span>
                <div class="flex gap-2 flex-wrap">
                  <div
                    class="hair-deselect relative flex justify-center items-center bg-gray default-border w-[18px] h-[18px] p-2 rounded-sm hover:bg-gray-500 hover:border-gray-400 focus-visible:outline-none focus-visible:border-white focus-visible:bg-cyan has-[:checked]:bg-cyan has-[:checked]:border-transparent"
                  >
                    <img src="/assets/icons/x-button-gray.svg" class="w-4 h-4" alt="Empty button" />
                    <input type="radio" name="hair" :value="null" v-model="selectedHairId" class="h-full w-full absolute left-0 top-0 m-0 z-10 hover:cursor-pointer focus-visible:outline-offset-0 focus-visible:outline-white" />
                  </div>
                  <div
                    v-for="hair in filteredHairs"
                    class="relative flex justify-center items-center bg-gray default-border w-[18px] h-[18px] p-2 rounded-sm hover:bg-gray-500 hover:border-gray-400 focus-visible:outline-none focus-visible:border-gray-300 focus-visible:bg-gray-500 has-[:checked]:bg-cyan has-[:checked]:border-transparent overflow-hidden"
                  >
                    <div class="absolute inset-0 flex items-center justify-center">
                      <img class="h-16 object-contain scale-[1] mt-8 origin-center" :src="config.server_endpoint + '/textures/sprites/' + hair.sprite + '/front.png'" alt="Hair sprite" />
                    </div>
                    <input type="radio" name="hair" :value="hair.id" v-model="selectedHairId" class="h-full w-full absolute left-0 top-0 m-0 z-10 hover:cursor-pointer focus-visible:outline-offset-0 focus-visible:outline-white" />
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div v-else>
        <img class="w-20 invert-80" src="/assets/icons/loading-icon1.svg" alt="Loading" />
      </div>
      <div class="w-2/3 button-wrapper flex self-center justify-center lg:justify-end gap-4 max-w-[860px]" v-if="!isLoading">
        <template v-if="!isCreatingCharacter">
          <button class="btn-empty min-w-48" @click.stop="gameStore.disconnectSocket()">Back</button>
          <button class="btn-cyan min-w-48 disabled:bg-cyan-800 disabled:cursor-not-allowed" :disabled="!selectedCharacterId" @click="loginWithCharacter()">Play now</button>
        </template>
        <template v-else>
          <button class="btn-empty min-w-48" @click="cancelCharacterCreation">Cancel</button>
          <button class="btn-cyan min-w-48" @click="createCharacter">Create</button>
        </template>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import config from '@/application/config'
import { SocketEvent } from '@/application/enums'
import { type CharacterHair, type Character as CharacterT, type Map } from '@/application/types'
import { useSoundComposable } from '@/composables/useSoundComposable'
import { socketManager } from '@/managers/SocketManager'
import { CharacterHairStorage, CharacterTypeStorage } from '@/storage/storages'
import { useGameStore } from '@/stores/gameStore'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'

const characterCreationSettings = {
  maxCharacters: 4,
  minNameLength: 3,
  maxNameLength: 20,
  defaultGender: 'MALE' as const
}

const { playSound } = useSoundComposable()
const gameStore = useGameStore()
const isLoading = ref<boolean>(true)
const characters = ref<CharacterT[]>([])
const selectedCharacterId = ref<string | null>(null)
const newNickname = ref<string>('')
const newCharacterName = ref<string>('')
const characterHairs = ref<CharacterHair[]>([])
const selectedHairId = ref<string | null>(null)
const defaultCharacterTypeId = ref<string>('')
const isCreatingCharacter = ref<boolean>(false)
const selectedGender = ref()

const selectedHairColor = ref<string | null>(null)
const uniqueHairColors = computed(() => {
  return [...new Set(characterHairs.value.map((hair) => hair.color))]
})

const filteredHairs = computed(() => {
  if (!selectedHairColor.value) return characterHairs.value
  return characterHairs.value.filter((hair) => hair.color === selectedHairColor.value)
})

function getHairColorStyle(color: string | null) {
  return {
    backgroundColor: color,
    border: selectedHairColor.value === color ? '1px solid white' : '1px solid rgba(255, 255, 255, 0.2)'
  }
}

function startCharacterCreation() {
  isCreatingCharacter.value = true
  selectedCharacterId.value = null
  newCharacterName.value = ''
  selectedHairId.value = null
  selectedHairColor.value = null
  selectedGender.value = characterCreationSettings.defaultGender
}

function cancelCharacterCreation() {
  isCreatingCharacter.value = false
  newCharacterName.value = ''
  selectedHairId.value = null
  selectedHairColor.value = null
}

// Fetch characters
setTimeout(() => {
  socketManager.emit(SocketEvent.CHARACTER_LIST)
}, 750)

socketManager.on(SocketEvent.CHARACTER_LIST, (data: any) => {
  characters.value = data
  isLoading.value = false
})

function loginWithCharacter() {
  if (!selectedCharacterId.value) return

  socketManager.emit(
    SocketEvent.CHARACTER_CONNECT,
    {
      characterId: selectedCharacterId.value,
      characterHairId: selectedHairId.value,
      newNickname: newNickname.value
    },
    (response: { character: CharacterT; map: Map; characters: CharacterT[] }) => {
      gameStore.setCharacter(response.character)
    }
  )
}

// Create character logics
function createCharacter() {
  if (newCharacterName.value.length < characterCreationSettings.minNameLength || newCharacterName.value.length > characterCreationSettings.maxNameLength) {
    return
  }

  socketManager.emit(
    SocketEvent.CHARACTER_CREATE,
    {
      name: newCharacterName.value,
      gender: selectedGender.value,
      hairId: selectedHairId.value
    },
    (success: boolean) => {
      if (success) {
        cancelCharacterCreation()
        socketManager.emit(SocketEvent.CHARACTER_LIST)
      }
    }
  )
}

// Watch changes for selected character and update hairs
watch(selectedCharacterId, (characterId) => {
  if (!characterId) return
  newNickname.value = ''
  isCreatingCharacter.value = false
  selectedHairId.value = characters.value.find((c) => c.id == characterId)?.characterHair ?? null
})

onMounted(async () => {
  await playSound('/assets/music/intro.mp3')
  const characterHairStorage = new CharacterHairStorage()
  const characterTypeStorage = new CharacterTypeStorage()
  characterHairs.value = await characterHairStorage.getAll()

  // Get the first available character type for preview
  const types = await characterTypeStorage.getAll()
  const defaultType = types.find((type) => type.isSelectable)
  if (defaultType) {
    defaultCharacterTypeId.value = defaultType.id
  }
})

onBeforeUnmount(() => {
  socketManager.off(SocketEvent.CHARACTER_LIST)
  socketManager.off(SocketEvent.CHARACTER_CONNECT)
  socketManager.off(SocketEvent.CHARACTER_CREATE)
})
</script>
