<script lang="ts" setup>
import { intervalToDuration, addMinutes, addSeconds, isAfter } from 'date-fns';
import { useNow } from '@vueuse/core';
import {
  useExamStore,
  useBasicStore,
  useAdvancedStore,
} from '~/stores/examStore';

definePageMeta({ middleware: 'exam' });

const examStore = useExamStore();
const basicStore = useBasicStore();
const advancedStore = useAdvancedStore();
await callOnce(() => examStore.mildReset(), { mode: 'navigation' });

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function preventRefresh(e: any) {
  e.preventDefault();
  e.returnValue = ''; // polyfill for older chrome
}

const now = ref('basic');

const nowTime = useNow();
const timeEnd = addMinutes(new Date(), 25);

const questionEnd = ref(addSeconds(new Date(), 20));

const mediaLoaded = ref(false);

const time = ref({
  total: computed(() =>
    intervalToDuration({
      start: nowTime.value,
      end: timeEnd,
    }),
  ),
  question: computed(() => {
    const interval = intervalToDuration({
      start: nowTime.value,
      end: questionEnd.value,
    });
    if (Object.hasOwn(interval, 'seconds') && interval.seconds != undefined) {
      return interval.seconds;
    } else {
      return 0;
    }
  }),
  phase: 'set-basic',
});

function changeQuestionTimeAfterNext() {
  if (time.value.phase == 'set-basic') {
    time.value.phase = 'start-basic';
    questionEnd.value = addSeconds(new Date(), 15);
  } else if (time.value.phase == 'start-basic') {
    if (now.value == 'basic') {
      time.value.phase = 'set-basic';
      mediaLoaded.value = false;
      questionEnd.value = addSeconds(new Date(), 20);
    } else {
      time.value.phase = 'set-advanced';
      questionEnd.value = addSeconds(new Date(), 50);
    }
  } else if (time.value.phase == 'set-advanced') {
    questionEnd.value = addSeconds(new Date(), 50);
  }
}

function onMediaLoad() {
  mediaLoaded.value = true;
}

function clickNext() {
  if (ending.value) {
    endExam();
  }
  if (time.value.phase != 'set-basic') {
    next();
  }
  changeQuestionTimeAfterNext();
}

onMounted(() => {
  useHead({
    title: `${$t('question')} 1/20`,
  });
  window.addEventListener('beforeunload', preventRefresh);

  watchEffect(() => {
    if (isAfter(nowTime.value, timeEnd)) endExam();
  });

  watchEffect(() => {
    if (now.value === 'basic')
      useHead({ title: `${$t('question')} ${countBasic.value + 1}/20` });
    if (now.value === 'advanced')
      useHead({ title: `${$t('question')} ${countAdvanced.value + 1}/12` });
  });

  watchEffect(() => {
    if (mediaLoaded.value == false && time.value.phase == 'start-basic') {
      questionEnd.value = addSeconds(new Date(), 15);
    }
    if (time.value.question < 0 && ending.value == false) {
      clickNext();
    }
  });
});

onBeforeUnmount(() => {
  window.removeEventListener('beforeunload', preventRefresh);
});

const {
  data: dataBasic,
  error: errorBasic,
  status: statusBasic,
} = await useLazyFetch<BasicQuestion[]>(`/api/basic`, {
  query: {
    category: examStore.category,
    lang: examStore.lang,
  },
});

const {
  data: dataAdvanced,
  error: errorAdvanced,
  status: statusAdvanced,
} = await useLazyFetch<AdvancedQuestion[]>(`/api/advanced`, {
  query: {
    category: examStore.category,
    lang: examStore.lang,
  },
});

const countBasic = ref(0);
const countAdvanced = ref(-1);

const answer = ref<string>('');

const ending = ref(false);

const questionBasic = computed<BasicQuestion | undefined>(() =>
  dataBasic.value?.at(countBasic.value),
);
const questionAdvanced = computed<AdvancedQuestion | undefined>(() =>
  dataAdvanced.value?.at(countAdvanced.value),
);

const question = computed(() => {
  if (now.value === 'basic') return questionBasic.value;
  if (now.value === 'advanced') return questionAdvanced.value;
  return null;
});

const result: Ref<ResultEndType> = ref({
  basic: [],
  advanced: [],
});

function next() {
  if (examStore.end == false) {
    result.value[now.value as keyof ResultEndType].push({
      question: question.value,
      chosen_answer: answer.value,
      correct_answer: question.value?.correct_answer ?? null,
      chosen_is_correct: answer.value == question.value?.correct_answer,
    });
    answer.value = '';
  } else {
    console.error('next() incorrectly executed - exam has already ended.');
  }
  if (now.value === 'basic') {
    if (countBasic.value + 1 <= 19) {
      countBasic.value++;
    } else {
      now.value = 'advanced';
      countAdvanced.value++;
    }
  } else if (now.value === 'advanced') {
    if (countAdvanced.value + 1 <= 11) {
      countAdvanced.value++;
    }
    if (countAdvanced.value + 1 >= 12) {
      ending.value = true;
    }
  }
}

const localePath = useLocalePath();

function endExam() {
  loading.value = true;
  while (ending.value == false) {
    if (time.value.phase != 'set-basic') {
      next();
    }
    changeQuestionTimeAfterNext();
  }
  next();
  basicStore.set(result.value.basic);
  advancedStore.set(result.value.advanced);
  examStore.setEnd(true);
  if (
    basicStore.basic == result.value.basic &&
    advancedStore.advanced == result.value.advanced &&
    examStore.end
  ) {
    return navigateTo(localePath(`result`), { replace: true });
  } else {
    return navigateTo(localePath(`anomaly`));
  }
}

const loading = ref(false);

const showEndModal = ref(false);
</script>

<template>
  <div>
    <!-- as in to transition to the next page -->
    <LoadingScreen v-if="loading" />
    <div v-if="statusBasic === 'success' && statusAdvanced === 'success'">
      <div class="grid grid-cols-4 min-h-dvh">
        <div class="col-span-3 flex flex-col">
          <BarTop
            :points="question?.weight"
            :category="examStore.category"
            :time-remaining="time.total"
          />
          <MediaBox
            :media-path="question?.media_url"
            :phase="time.phase"
            @mediaload="onMediaLoad()"
          />
          <QuestionBasic
            v-if="now === 'basic'"
            v-model="answer"
            phase="exam"
            :question="questionBasic"
          />
          <QuestionAdvanced
            v-else-if="now === 'advanced'"
            v-model="answer"
            phase="exam"
            :question="questionAdvanced"
          />
        </div>
        <BarRightExam
          :count-basic="countBasic"
          :count-advanced="countAdvanced"
          :now="now"
          :ending="ending"
          :set-basic="time.phase == 'set-basic'"
          :time="time.question"
          :phase="time.phase"
          @show-end-modal="showEndModal = true"
          @next-question="clickNext()"
          @end-exam="endExam()"
          @next-time="changeQuestionTimeAfterNext()"
        />
      </div>
    </div>
    <div v-else-if="statusBasic === 'error' || statusAdvanced === 'error'">
      {{ $t('anAPIErrorOccured') }}:<br />
      <code class="text-sm">{{ errorBasic }}</code>
      <br />
      <code class="text-sm">{{ errorAdvanced }}</code>
    </div>
    <LoadingScreen v-else />
    <EndModal
      :show-modal="showEndModal"
      @hide-end-modal="showEndModal = false"
      @end-exam="endExam()"
    />
  </div>
</template>
