<template>
  <div class="w-full">
    <!-- Number to find -->
    <div class="p-1 mx-auto mb-4 w-fit text-cyan-500">
      <span class="font-mono text-4xl">{{ result ? result : '???' }}</span>
    </div>

    <!-- Start button -->
    <!-- TODO: fix animation -->
    <Transition name="zero_height">
      <div
        class="text-center"
        v-if="gameState <= GameState.Waiting">
        <div v-if="isDaily">
          {{ t('dailyDescription') }}<br>
        </div>

        <button
          @click="startGame"
          class="py-2 px-4 mt-4 btn-border">
          {{ t('startGame') }}
        </button>
      </div>
    </Transition>

    <!-- PLAQUETTES -->
    <PlaquettesList
      ref="cmpPlaquettes"
      :plaquettes="shownPlaquettes"
      @click-number="selectNumber" />

    <Transition name="slide_up">
      <div v-if="gameIsRunning">
        <!-- OPERATORS -->
        <OperatorsList @click="selectOperator" />

        <!-- Divider -->
        <div class="my-4 mx-auto max-w-sm border-b border-cyan-500/50" />

        <!-- List of Operations -->
        <OperationsList v-show="gameIsRunning" />
      </div>
    </Transition>

    <Transition name="slide_up">
      <div
        v-if="isEndGame"
        class="flex flex-row justify-evenly items-center mx-auto mt-8 max-w-sm">
        <span
          v-if="isResultPerfect"
          v-html="t('endGame.victoryLabel')" />
        <span
          v-else
          v-html="t('endGame.failureLabel')" />
        <button
          v-if="!isDaily"
          class="btn-border"
          @click="reboot">
          {{ t('playAgain') }}
        </button>
        <button
          v-else
          class="btn-border">
          {{ t('share') }}
        </button>
      </div>
    </Transition>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'

import {
  getEmptyOperation,
  isOperationReady,
  isOperationResultValid,
  isSolvable,
  operate,
} from '@/algo'
import OperationsList from '@/components/OperationsList.vue'
import OperatorsList from '@/components/OperatorsList.vue'
import PlaquettesList from '@/components/PlaquettesList.vue'
import {
  clearOperationsList,
  currentOperation,
  gameIsRunning,
  gameState,
  isEndGame,
  isResultPerfect,
  operations,
  plaquettes,
  result,
} from '@/composables/game-state'
import { hasPlayed } from '@/composables/statistics'
import { GameState, pools } from '@/globals'
import { OperatorType, Plaquette } from '@/types'
import {
  getCurrentSessionKey,
  randItem,
  random,
  randRange,
  setDailyPRNG,
  setMathPRNG,
} from '@/utils'

const { t } = useI18n() // call `useI18n`, and spread `t` from  `useI18n` returning

/*
 * Computed & refs
 */

const difficultyLevel = ref<1 | 2>(1)
const cmpPlaquettes = ref<InstanceType<typeof PlaquettesList>>()

const isDaily = computed(() => useRoute()?.name === 'daily')
const shownPlaquettes = computed(() =>
  gameIsRunning.value ? plaquettes.value : [],
)

/*
 * Watchers
 */

watch(
  currentOperation,
  op => {
    if (isOperationReady(op) && isOperationResultValid(op) && !op.result) {
      op.result = {
        free: true,
        value: operate(op.operator!, op.left!.value, op.right!.value),
      }
      if (operations.length < 5 && !isEndGame.value) {
        plaquettes.value.push(op.result)
        operations.push(getEmptyOperation())
      }
    }
  },
  { deep: true },
)

function startGame(): void {
  gameState.value = GameState.Loading
  setTimeout(() => (gameState.value = GameState.Playing), 500)
  setTimeout(() => {
    if (cmpPlaquettes.value) {
      // Remove the animation delay for the plaquettes,
      // or else the mouse hover effect is delayed until the first click
      cmpPlaquettes.value.initDelay = 0
    }
  }, 2000)
}

function selectNumber(p: Plaquette): void {
  if (isEndGame.value) return

  const op = currentOperation.value
  if (!p.free) return

  if (!op.left) {
    op.left = p
    p.free = false
  }
  else if (!op.right) {
    op.right = p
    p.free = false
  }
}

/*
 * Functions
 */

function selectOperator(o: OperatorType): void {
  if (isEndGame.value) return
  currentOperation.value.operator = o
}

function reboot(): void {
  gameState.value = GameState.Playing

  // The daily number is >= 500 to have a minimum challenge
  const minValue = isDaily.value ? 500 : 101

  do {
    // Find a problem
    // result.value = randRange(101, 1000)
    difficultyLevel.value = randItem([1, 1, 1, 1, 2])
    result.value = (() => {
      switch (difficultyLevel.value) {
        case 1:
          return randRange(minValue, 1000)
        case 2:
          return randRange(minValue, 1000)
      }
    })()
    // result.value = 29
    // Reset Operations list
    clearOperationsList()

    // Generate result and plaquettes
    plaquettes.value = []
    const poolCopy = [...pools[difficultyLevel.value]]
    for (let i = 0; i < 6; ++i) {
      const rndItem = Math.floor(random() * poolCopy.length)
      const el = poolCopy.splice(rndItem, 1)[0]
      plaquettes.value.push({ value: el, free: true })
    }
    // plaquettes.value = [4, 8, 10, 25, 50, 100].map(value => ({
    //   free: true,
    //   value,
    // }))
    // Solve it
  } while (
    !isSolvable(
      result.value,
      plaquettes.value.map(p => p.value),
    )
  )
  plaquettes.value.sort((a, b) => a.value - b.value)
}

/*
 * Hooks
 */

onMounted(() => {
  if (!isDaily.value && !hasPlayed(getCurrentSessionKey())) {
    const router = useRouter()
    router.replace({ name: 'home' })
    return
  }

  if (isDaily.value) {
    console.log('daily rng')
    setDailyPRNG()
  }
  else {
    console.log('normal rng')
    setMathPRNG()
  }

  result.value = 0

  // Wait until after the page transion to generate the number
  setTimeout(() => {
    reboot()
    gameState.value = GameState.Waiting
  }, 800)
  // But make sure the operations list is empty asap
  clearOperationsList()
})

onUnmounted(() => {
  gameState.value = GameState.Waiting
})
</script>
