<script setup lang="ts">
import ItRadioGroup from "@/components/ui/ItRadioGroup.vue";
import ItTextarea from "@/components/ui/ItTextarea.vue";
import { graphql } from "@/gql";
import FeedbackCompletition from "@/pages/learningPath/learningContentPage/feedback/FeedbackCompletition.vue";
import {
  PERCENTAGES,
  RATINGS,
  YES_NO,
} from "@/pages/learningPath/learningContentPage/feedback/feedback.constants";
import LearningContentMultiLayout from "@/pages/learningPath/learningContentPage/layouts/LearningContentMultiLayout.vue";
import type { LearningContentFeedback } from "@/types";
import { useMutation } from "@urql/vue";
import { useRouteQuery } from "@vueuse/router";
import log from "loglevel";
import { computed, onMounted, reactive, ref } from "vue";
import { useTranslation } from "i18next-vue";
import { useCourseSessionDetailQuery, useCurrentCourseSession } from "@/composables";

const props = defineProps<{
  content: LearningContentFeedback;
}>();
const courseSession = useCurrentCourseSession();
const courseSessionDetailResult = useCourseSessionDetailQuery();

const { t } = useTranslation();

const stepNo = useRouteQuery("step", "0", { transform: Number, mode: "push" });

const title = computed(
  () => `«${props.content.circle?.title}»: ${t("feedback.areYouSatisfied")}`
);

const circleExperts = computed(() => {
  if (props.content?.circle?.slug) {
    return courseSessionDetailResult.filterCircleExperts(props.content.circle.slug);
  }
  return [];
});

const stepLabels = [
  t("general.introduction"),
  t("feedback.satisfactionLabel"),
  t("feedback.goalAttainmentLabel"),
  t("feedback.proficiencyLabel"),
  t("feedback.preparationTaskClarityLabel"),
  t("feedback.instructorCompetenceLabel"),
  t("feedback.instructorRespectLabel"),
  t("feedback.instructorOpenFeedbackLabel"),
  t("feedback.recommendLabel"),
  t("feedback.coursePositiveFeedbackLabel"),
  t("feedback.courseNegativeFeedbackLabel"),
  t("general.submission"),
];

const numSteps = stepLabels.length;

// noinspection GraphQLUnresolvedReference -> mute IntelliJ warning
const sendFeedbackMutation = graphql(`
  mutation SendFeedbackMutation(
    $courseSessionId: ID!
    $learningContentId: ID!
    $data: GenericScalar!
    $submitted: Boolean
  ) {
    send_feedback(
      course_session_id: $courseSessionId
      learning_content_page_id: $learningContentId
      data: $data
      submitted: $submitted
    ) {
      feedback_response {
        id
        data
        submitted
      }
      errors {
        field
        messages
      }
    }
  }
`);

const feedbackSubmitted = ref(false);

const { executeMutation } = useMutation(sendFeedbackMutation);

interface FeedbackData {
  [key: string]: number | string | null;
}

const feedbackData: FeedbackData = reactive({
  satisfaction: null,
  goal_attainment: null,
  proficiency: null,
  preparation_task_clarity: null,
  instructor_competence: null,
  instructor_respect: null,
  instructor_open_feedback: "",
  would_recommend: null,
  course_positive_feedback: "",
  course_negative_feedback: "",
});

const questionData = [
  {
    modelKey: "satisfaction",
    items: RATINGS,
    component: ItRadioGroup,
  },
  {
    modelKey: "goal_attainment",
    items: RATINGS,
    component: ItRadioGroup,
  },
  {
    modelKey: "proficiency",
    items: PERCENTAGES,
    component: ItRadioGroup,
  },
  {
    modelKey: "preparation_task_clarity",
    items: YES_NO,
    component: ItRadioGroup,
  },
  {
    modelKey: "instructor_competence",
    items: RATINGS,
    component: ItRadioGroup,
  },
  {
    modelKey: "instructor_respect",
    items: RATINGS,
    component: ItRadioGroup,
  },
  {
    modelKey: "instructor_open_feedback",
    component: ItTextarea,
  },
  {
    modelKey: "would_recommend",
    items: YES_NO,
    component: ItRadioGroup,
  },
  {
    modelKey: "course_positive_feedback",
    component: ItTextarea,
  },
  {
    modelKey: "course_negative_feedback",
    component: ItTextarea,
  },
];

const previousStep = () => {
  if (stepNo.value > 0) {
    stepNo.value -= 1;
  }
};

const nextStep = () => {
  if (stepNo.value < numSteps && hasStepValidInput(stepNo.value)) {
    stepNo.value += 1;
  }
  log.debug(`next step ${stepNo.value} of ${numSteps}`);
  mutateFeedback(feedbackData);
};

function hasStepValidInput(stepNumber: number) {
  const question = questionData[stepNumber - 1];
  if (question) {
    if (
      [
        "instructor_open_feedback",
        "course_negative_feedback",
        "course_positive_feedback",
      ].includes(question.modelKey)
    ) {
      // text response questions need to have a "truthy" value (not "" or null)
      return feedbackData[question.modelKey];
    } else {
      // other responses need to have data, can be `0` or `false`
      return feedbackData[question.modelKey] !== null;
    }
  }
  return true;
}

function mutateFeedback(data: FeedbackData, submit = false) {
  log.debug("mutate feedback", feedbackData);
  return executeMutation({
    courseSessionId: courseSession.value.id,
    learningContentId: props.content.id,
    data: data,
    submitted: submit,
  })
    .then((result) => {
      log.debug("feedback mutation result", result);
      if (result.data?.send_feedback?.feedback_response?.data) {
        const responseData = result.data.send_feedback.feedback_response.data;
        if (!responseData.instructor_open_feedback) {
          responseData.instructor_open_feedback = "";
        }
        if (!responseData.course_negative_feedback) {
          responseData.course_negative_feedback = "";
        }
        if (!responseData.course_positive_feedback) {
          responseData.course_positive_feedback = "";
        }
        Object.assign(feedbackData, responseData);
        log.debug("feedback data", feedbackData);
        feedbackSubmitted.value =
          result.data?.send_feedback?.feedback_response?.submitted || false;
      }
    })
    .catch((e) => log.error(e));
}

onMounted(async () => {
  log.debug("Feedback mounted");
  await mutateFeedback({});
  if (feedbackSubmitted.value) {
    stepNo.value = numSteps - 1;
  }
});
</script>

<template>
  <LearningContentMultiLayout
    :title="title"
    sub-title="Feedback"
    :learning-content="content"
    :show-start-button="stepNo === 0"
    :show-next-button="stepNo > 0 && stepNo + 1 < numSteps"
    :disable-next-button="!hasStepValidInput(stepNo)"
    :show-previous-button="stepNo > 0 && !feedbackSubmitted"
    :show-exit-button="stepNo + 1 === numSteps"
    :current-step="stepNo"
    :steps-count="numSteps"
    :start-badge-text="$t('general.introduction')"
    :end-badge-text="$t('general.submission')"
    :base-url="props.content.frontend_url"
    close-button-variant="close"
    @previous="previousStep()"
    @next="nextStep()"
  >
    <div>
      <p v-if="stepNo === 0" class="mt-10">
        {{
          $t("feedback.intro", {
            name: `${circleExperts[0]?.first_name} ${circleExperts[0]?.last_name}`,
          })
        }}
      </p>
      <p v-if="stepNo > 0 && stepNo + 1 < numSteps" class="pb-2">
        {{ stepLabels[stepNo] }}
      </p>
      <div v-for="(question, index) in questionData" :key="index">
        <!-- eslint-disable -->
        <!-- eslint does not like the dynamic v-model... -->
        <component
          :is="question.component"
          v-if="index + 1 === stepNo"
          v-model="feedbackData[question.modelKey] as any"
          :items="question['items']"
          :cy-key="question.modelKey"
        />
        <!-- eslint-enable -->
      </div>
      <FeedbackCompletition
        v-if="stepNo === 11"
        :avatar-url="circleExperts[0].avatar_url"
        :title="
          $t('feedback.completionTitle', {
            name: `${circleExperts[0].first_name} ${circleExperts[0].last_name}`,
          })
        "
        :description="$t('feedback.completionDescription')"
        :feedback-sent="feedbackSubmitted"
        @send-feedback="mutateFeedback(feedbackData, true)"
      />
    </div>
  </LearningContentMultiLayout>
</template>
