<script setup lang="ts">
import { computed, inject, onMounted, onUnmounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { useGameStore } from '@/stores/game'
import { storeToRefs } from 'pinia'
import type { LoggingService } from '@/services/LoggingService'
import type { GameService } from '@/services/GameService'
import type { MatchSessionOptions, MatchSessionDto } from '@/common/interfaces'
import { useEventBusStore } from '@/stores/eventBus'
import { copyToclipboard, wait } from '@/common/helpers'
import { useGameOptionsStore } from '@/stores/gameOptions'
import MatchConfiguration from '@/components/MatchConfiguration.vue'
import { useI18n } from 'vue-i18n'
import { SessionExpiredError } from '@/common/errors/SessionExpiredError'
import type { AuthenticationService } from '@/services/AuthenticationService'

let teamedWith = ref<string | undefined>(undefined)

let matchSessions = ref<MatchSessionDto[]>([])
let dataInterval: any
let loadingSessions = ref<boolean>(false)

const router = useRouter()
const gameStore = useGameStore()
const gameOptionsStore = useGameOptionsStore()

const socketService: any = inject('socket')
const gameService: GameService = inject<GameService>('game') as GameService
const logger: LoggingService = inject<LoggingService>('logger') as LoggingService
const authService: AuthenticationService = inject<AuthenticationService>(
  'auth',
) as AuthenticationService

const { sessionState, isSessionStarted, playerState, amIHost, readyForStart } =
  storeToRefs(gameStore)
const { gameOptions } = storeToRefs(gameOptionsStore)
const { updateSessionState, updatePlayerState, updateGameState } = gameStore
const { t } = useI18n()

const eventBus = useEventBusStore()
eventBus.subscribe('window-before-unload', () => {
  logger.debug('Window before unload')
})

async function createMatch(options: MatchSessionOptions) {
  logger.debug('Creating match')
  await socketService.connect()
  gameOptions.value = options
  const sessionId = await gameService.createMatchSession(options)
  socketService.joinRoom(`room-${sessionId}`)
  logger.debug('Match created successfully')
  // router.push({ name: 'match', params: { id } })
}

async function setPlayerReady() {
  logger.debug('Starting game')
  if (!sessionState.value) {
    logger.error('No session found')
    return
  }
  if (!playerState.value) {
    logger.error('No player found')
    return
  }
  await socketService.sendMessage('client:set-player-ready', {
    userId: playerState.value.id,
    sessionId: sessionState.value.id,
  })
}

async function startMatch() {
  const sessionId = sessionState?.value?.id
  const playerId = playerState?.value?.id
  if (sessionId) {
    await socketService.sendMessageWithAck('client:start-session', {
      sessionId: sessionId,
      playerId: playerId,
      teamedWith: teamedWith.value,
    })
  }
}

async function cancelMatch() {
  logger.debug('Cancelling match')
  if (sessionState?.value?.id) {
    if (amIHost.value) {
      await gameService.cancelMatchSession(sessionState?.value?.id)
    } else {
      //TODO: await gameService.leaveMatchSession(sessionState?.value?.id)
    }

    updateSessionState(undefined)
    updatePlayerState(undefined)
    updateGameState(undefined)
    teamedWith.value = undefined
  }
}

eventBus.subscribe('server:match-starting', (data) => {
  const session = data.sessionState as MatchSessionDto
  updateSessionState(session)
  router.push({ name: 'game', params: { id: session.id } })
})

async function joinMatch(id: string) {
  if (id) {
    await socketService.connect(id)
    socketService.joinRoom(`room-${id}`)
    await gameService.joinMatchSession(id)
  }
}
async function deleteMatch(id: string) {
  if (id) {
    await socketService.connect()
    await gameService.cancelMatchSession(id)
    loadData()
  }
}

const playersToTeamUpWith = computed(() => {
  return (
    sessionState?.value?.players.filter((player) => player.id !== sessionState?.value?.creator) ||
    []
  )
})

const canStart = computed(() => {
  const players = sessionState?.value?.players || []
  const options = gameOptions.value
  const allReady = (players.length || 0) > 0 && players.every((player) => player.ready)
  return (!options?.teamed && allReady) || (options?.teamed && !!teamedWith.value && allReady)
})

const isMultiplayer = computed(
  () => (sessionState?.value?.options?.numPlayers || gameOptions.value?.numPlayers || 0) > 1,
)

async function loadData() {
  loadingSessions.value = true
  let listResponse
  try {
    listResponse = await gameService.listMatchSessions()
  } catch (error: any) {
    if (error instanceof SessionExpiredError) {
      authService.removePersistence()
      router.push({ name: 'landing' })
    } else {
      logger.error('Error loading match sessions', error)
    }
    return
  }

  loadingSessions.value = false
  matchSessions.value = listResponse.data
}

onMounted(() => {
  loadData()
  dataInterval = setInterval(loadData, 10000)
})

onUnmounted(() => {
  clearInterval(dataInterval)
})

function copy(sessionSeed: string) {
  copyToclipboard(sessionSeed)
}

let selectedTab = ref('create-tab')
const isCreateTab = computed(() => selectedTab.value === 'create-tab')
const isJoinTab = computed(() => selectedTab.value === 'join-tab')
const isTournamentTab = computed(() => selectedTab.value === 'torunaments-tab')

const tabs = computed<any[]>((): any => [
  { label: t('create-session'), id: 'create-tab', disabled: false },
  {
    label: t('join-a-multiplayer-session', matchSessions.value.length),
    id: 'join-tab',
    disabled: matchSessions.value.length <= 0,
  },
  { label: t('tournaments'), id: 'torunaments-tab', disabled: true },
])

async function tabClick(tab: any) {
  selectedTab.value = tab.id
}

function onCreateMatch(options: MatchSessionOptions) {
  createMatch(options)
}

async function onStartSingleMatch(options: MatchSessionOptions) {
  await createMatch(options)
  await wait(1000)
  startMatch()
}
</script>

<template>
  <div class="container home">
    <section class="mt-4">
      <!-- <h1 class="title is-2">
        {{ $t('welcome-to-the-user-username-s-home-page', [user.username]) }}
      </h1> -->
      <!-- Tabs -->
      <div class="block" v-if="!isSessionStarted">
        <div class="tabs is-centered">
          <ul>
            <li
              v-bind:key="tab.label"
              v-for="tab in tabs"
              :class="{ 'is-active': selectedTab === tab.id, 'is-disabled': tab.disabled }"
            >
              <a @click="() => tabClick(tab)">{{ tab.label }}</a>
            </li>
          </ul>
        </div>
        <!-- Tabs End -->
        <!-- Match Configuration -->
        <section class="section pt-5" v-if="isCreateTab">
          <MatchConfiguration
            @create-match="onCreateMatch"
            @start-single-match="onStartSingleMatch"
          />
        </section>
        <!-- Match Configuration End -->
        <!-- Join a Multiplayer Session -->
        <section class="section available-sessions" v-if="isJoinTab">
          <div class="block">
            <div v-if="matchSessions.length === 0">
              <p>{{ $t('no-sessions-available') }}</p>
            </div>
            <div v-else class="fixed-grid has-3-cols">
              <div class="grid">
                <div class="cell" v-for="session in matchSessions" :key="session.id">
                  <div class="card">
                    <div class="card-content">
                      <p class="title is-6">{{ session.name }}</p>
                      <p>{{ $t('id-session-_id', [session._id]) }}</p>
                      <p>{{ $t('players-session-players-length', [session.players.length]) }}</p>
                      <p>
                        {{ $t('seed-session-seed', [session.seed]) }}
                        <button class="button is-small is-ghost" @click="() => copy(session.seed)">
                          {{ $t('copy') }}
                        </button>
                      </p>
                      <p>{{ $t('status-session-status', [session.status]) }}</p>
                      <div class="buttons is-centered mt-6">
                        <button
                          class="button is-primary"
                          @click.once.prevent="() => joinMatch(session._id)"
                        >
                          <span>{{ $t('join') }}</span>
                        </button>
                        <button
                          class="button is-text"
                          @click.once.prevent="() => deleteMatch(session._id)"
                        >
                          <span>{{ $t('delete') }}</span>
                        </button>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </section>
        <!-- Join a Multiplayer Session End -->
        <!-- Tournaments -->
        <section class="section" v-if="isTournamentTab"></section>
        <!-- Tournaments End -->
      </div>
      <div class="block" v-if="isSessionStarted && isMultiplayer">
        <h2 class="title is-4">{{ sessionState?.name }}</h2>
        <h6 class="title is-size-5">Players</h6>
        <div v-for="player in sessionState?.players" :key="player.id">
          <p>{{ player.name }} ({{ player.ready ? 'Ready' : 'Not ready' }})</p>
        </div>
        <div class="mt-4" v-if="amIHost && gameOptions?.teamed && playersToTeamUpWith.length > 0">
          <div class="field">
            <label for="background" class="label">Team up with</label>
            <div class="control">
              <div class="select">
                <select v-model="teamedWith" name="teamedWidth">
                  <option v-for="player in playersToTeamUpWith" :key="player.id" :value="player.id">
                    {{ player.name }}
                  </option>
                </select>
              </div>
            </div>
          </div>
        </div>
        <div class="buttons mt-6">
          <button class="button is-dark" @click="setPlayerReady">
            <span v-if="!readyForStart">{{ $t('ready') }}</span
            ><span v-else>{{ $t('unready') }}</span>
          </button>
          <button
            class="button is-success"
            :disabled="!canStart"
            @click="startMatch"
            v-if="amIHost"
          >
            <span>{{ $t('start') }}</span>
          </button>

          <button class="button is-danger" @click="cancelMatch">
            <span>{{ $t('cancel') }}</span>
          </button>
        </div>
      </div>
    </section>
  </div>
</template>

<style scoped lang="scss"></style>
