<template>
  <div class="survey-page">
    <h1 class="survey-page__title">{{ title }}</h1>
    <div id="survey" />

    <solution
      :value="solution"
      v-if="showSolution"
    />
    <div v-if="surveyComplete">
      <a
        class="button button--primary"
        @click="reopen"
        >Übung bearbeiten</a
      >
    </div>
  </div>
</template>

<script lang="ts">
import '@/styles/survey.modern.css';
import '@/styles/survey.reset.css';
import '@/styles/_survey.scss';
import { css } from '@/survey.config';
import gql from 'graphql-tag';
import { Model, StylesManager } from 'survey-knockout';
// we are switching to the knockout version because the Vue version only works with Vue 2 (as of July 2022)

import SURVEY_QUERY from '@/graphql/gql/queries/surveyQuery.gql';
import UPDATE_ANSWER from '@/graphql/gql/mutations/updateAnswer.gql';

import { extractSurveySolutions } from '@/helpers/survey-solutions';
import { isTeacher } from '@/helpers/is-teacher';

import { meQuery } from '@/graphql/queries';

import { defineAsyncComponent } from 'vue';
import { matomoTrackEvent } from '@/helpers/matomo-client';
const Solution = defineAsyncComponent(() => import('@/components/content-blocks/Solution.vue'));

StylesManager.applyTheme('modern');

const MODULE_QUERY = gql`
  query ModuleSolutions($slug: String) {
    module(slug: $slug) {
      solutionsEnabled
      slug
    }
  }
`;

export default {
  props: ['id'],
  components: {
    Solution,
  },

  data() {
    return {
      survey: this.initSurvey(),
      currentPage: null,
      surveyData: null,
      title: '',
      module: {},
      completed: false,
      me: {
        permissions: [],
      },
      saveDisabled: false,
    };
  },

  computed: {
    surveyComplete() {
      return this.survey && this.survey.isCompleted;
    },
    showSolution() {
      return (this.module.solutionsEnabled || this.isTeacher) && !this.survey.isCompleted;
    },
    solution() {
      // todo: should this be done inside of Solution.vue?
      return {
        text: this.answers.reduce((previous, answer) => {
          if (!answer.answer) {
            return previous;
          }
          const type = answer.type;
          if (type === 'matrix' || type === 'matrixdropdown' || type === 'checkbox') {
            // wrap all the answers inside li tags and convert to a single string
            const answerText = answer.answer.map((a) => `<li class="solution-text__list-item">${a}</li>`).join('');
            return `
            ${previous}
            <h2 class="solution-text__heading">${answer.title}</h2>
            <ul class="solution-text__answer solution-text__list">${answerText}</ul>
            `;
          } else {
            return `
            ${previous}
             <h2 class="solution-text__heading">${answer.title}</h2>
             <p class="solution-text__answer">${answer.answer}</p>
             `;
          }
        }, ''),
      };
    },
    answers() {
      return this.currentPage && this.currentPage.elements
        ? this.currentPage.elements.reduce(extractSurveySolutions, [])
        : [];
    },
    isTeacher() {
      return isTeacher(this);
    },
  },

  mounted() {
    if (this.surveyData) {
      this.loadSurveyFromServer(this.surveyData);
    }
  },

  unmounted() {},
  methods: {
    initSurvey(data, answers) {
      let survey = new Model(data);
      const flatAnswers = {};
      for (let k in answers) {
        flatAnswers[k] = answers[k].answer;
      }

      if (Object.keys(flatAnswers).length > 0) {
        // answers are not empty
        survey.data = flatAnswers;
      }

      this.currentPage = survey.currentPage;

      const updatePage = (sender, { oldCurrentPage, newCurrentPage }) => {
        console.log(oldCurrentPage, newCurrentPage);
        this.currentPage = newCurrentPage;
      };

      const saveSurvey = (sender, { exit }) => {
        if (this.saveDisabled) {
          return;
        }

        this.completed = true;

        const data = {};

        for (let k in survey.data) {
          // if (survey.data.hasOwnProperty(k)) {
          if (Object.prototype.hasOwnProperty.call(survey.data, k)) {
            let question = sender.getQuestionByName(k);
            data[k] = {
              answer: survey.data[k],
              correct: question && question.correctAnswer ? question.correctAnswer : '',
            };
          }
        }
        if (Object.keys(data).length === 0) {
          // data is empty
          return;
        }
        const answer = {
          surveyId: this.id,
          data: JSON.stringify(data),
        };

        this.$apollo.mutate({
          mutation: UPDATE_ANSWER,
          variables: {
            input: {
              answer,
            },
          },
          update: (
            store,
            {
              data: {
                updateAnswer: { answer },
              },
            }
          ) => {
            const query = SURVEY_QUERY;
            const variables = { id: this.id };
            const { survey } = store.readQuery({ query, variables });
            if (survey) {
              const newData = {
                // data is already in use in parent scope
                survey: {
                  ...survey,
                  answer,
                },
              };
              store.writeQuery({ query, variables, data: newData });
            }
          },
        });
        if (exit) {
          matomoTrackEvent('Übung', 'Übung erfolgreich abgeschlossen', this.surveyData.title);
          this.$router.go(-1);
        } else {
          matomoTrackEvent('Übung', 'Übungsschritt abgeschlossen', this.surveyData.title);
        }
      };

      survey.onComplete.add((sender, options) => {
        saveSurvey(sender, {
          ...options,
          exit: true,
        });
      });
      survey.onCurrentPageChanged.add(saveSurvey);
      survey.onCurrentPageChanged.add(updatePage);

      survey.css = css;
      survey.locale = 'de';
      survey.showProgressBar = 'bottom';
      survey.pageNextText = 'Speichern & Weiter';

      survey.render('survey');
      return survey;
    },
    reopen() {
      this.saveDisabled = true; // disable saving, because resetting triggers a page change which we don't want to save
      this.completed = false;
      let data = this.survey.data; // save the data
      this.survey.clear();
      this.survey.data = data; // reapply it
      this.saveDisabled = false;
    },
    loadSurveyFromServer(survey) {
      let json = JSON.parse(survey.data);
      json.showTitle = false;
      json.showProgressBar = 'bottom';
      let answer = {};
      if (survey.answer && survey.answer.data) {
        answer = JSON.parse(survey.answer.data);
      }
      // we now need to traverse all the `pages` and all the `elements` inside them, which themselves have `elements`,
      // and we need to delete their `isRequired` keys
      json = {
        ...json,
        pages: json.pages.map((page) => {
          return {
            ...page,
            elements: page.elements?.map((element) => {
              return {
                ...element,
                elements: element.elements?.map((subElement) => {
                  return {
                    ...subElement,
                    isRequired: false,
                  };
                }),
              };
            }),
          };
        }),
      };

      if (!this.completed) {
        this.survey = this.initSurvey(json, answer);
      }
      this.title = json.title;
    },
  },

  apollo: {
    survey: {
      query: SURVEY_QUERY,
      variables() {
        return {
          id: this.id,
        };
      },
      manual: true,
      result({ data, loading }) {
        if (!loading) {
          this.surveyData = data.survey;
          this.loadSurveyFromServer(data.survey);
          const module = data.survey.module;
          matomoTrackEvent('Übung', 'Übung angezeigt', this.surveyData.title);

          this.$apollo.addSmartQuery('module', {
            query: MODULE_QUERY,
            variables: {
              slug: module.slug,
            },
          });
        }
      },
    },
    me: meQuery,
  },
};
</script>

<style scoped lang="scss">
@import 'styles/helpers';

.survey-page {
  max-width: 800px;
  display: grid;
  grid-template-rows: auto 1fr;
  grid-auto-rows: auto;
  grid-row-gap: $large-spacing;
  justify-self: center;
  padding: 100px 0;
  width: 100%;

  &__title {
    @include meta-title;
    margin: 0;
  }
}
</style>
