<template>
  <module
    :module="module"
    v-if="module.id"
    @editNote="editNote"
    @addNote="addNote"
    @bookmark="bookmark"
  />
</template>

<script>
import Module from '@/components/modules/Module.vue';
import log from 'loglevel';

import UPDATE_LAST_MODULE_MUTATION from '@/graphql/gql/mutations/updateLastModule.gql';
import UPDATE_MODULE_BOOKMARK_MUTATION from '@/graphql/gql/mutations/updateModuleBookmark.gql';
// import ME_QUERY from '@/graphql/gql/meQuery.gql';
import MODULE_FRAGMENT from '@/graphql/gql/fragments/moduleParts.gql';
import SCROLL_POSITION from '@/graphql/gql/local/scrollPosition.gql';
import SCROLL_TO_MUTATION from '@/graphql/gql/local/mutations/scrollTo.gql';

import meMixin from '@/mixins/me';
import MODULE_DETAILS_QUERY from '@/graphql/gql/queries/modules/moduleDetailsQuery.gql';
import ME_QUERY from '@/graphql/gql/queries/meQuery.gql';
import { setModuleEditMode } from '@/graphql/cache-operations';

export default {
  mixins: [meMixin],

  components: {
    Module,
  },

  data() {
    return {
      module: {},
      updateSent: false,
    };
  },

  beforeRouteLeave(to, _, next) {
    // toggle edit mode if leaving the module subtree
    if (this.module.inEditMode && to.path.indexOf('/module/') === -1) {
      setModuleEditMode(this.module.slug, false);
    }
    next();
  },

  apollo: {
    module() {
      return {
        query: MODULE_DETAILS_QUERY,
        variables: {
          slug: this.$route.params.slug,
        },
        result({
          data: {
            module: { id },
          },
        }) {
          if (!this.updateSent) {
            // log.debug(`=== updating result for module ${id} ===`);
            this.updateLastVisitedModule(id);
            this.updateSent = true;
          }
        },
        fetchPolicy: 'cache-first',
      };
    },
    scrollPosition: {
      query: SCROLL_POSITION,
    },
  },

  methods: {
    updateLastVisitedModule(moduleId) {
      // log.debug(`updating last visited module for module ${moduleId}`);
      if (!moduleId) {
        log.warn('no module id');
        return;
      }

      if (this.me.lastModule && this.me.lastModule.id === moduleId) {
        log.debug('same module already set as last module');
        return;
      }

      this.$apollo.mutate({
        mutation: UPDATE_LAST_MODULE_MUTATION,
        variables: {
          input: {
            id: moduleId,
          },
        },
        update: (
          store,
          {
            data: {
              updateLastModule: { lastModule },
            },
          }
        ) => {
          const { slug } = lastModule;
          // log.debug('updating last module', lastModule.id, slug);
          const query = ME_QUERY;
          let { me } = store.readQuery({
            query,
          });
          // me.lastModule = {
          //   id,
          //   slug,
          //   __typename: 'ModuleNode',
          // };

          let edges = [...me.recentModules.edges];
          const foundIndex = edges.findIndex((edge) => edge.node.slug === slug);
          if (foundIndex > -1) {
            edges = [...edges.slice(0, foundIndex), ...edges.slice(foundIndex + 1, edges.length)];
          }
          edges = [
            {
              node: lastModule,
              __typename: 'ModuleNodeEdge',
            },
            ...edges.slice(0, 2),
          ];
          const recentModules = {
            __typename: 'ModuleNodeConnection',
            edges,
          };
          const data = {
            me: {
              ...me,
              recentModules,
              lastModule: {
                ...lastModule,
                // todo: do we really need this? shouldn't the lastModule property already include this?
                __typename: 'ModuleNode',
              },
            },
          };
          store.writeQuery({
            query,
            data,
          });
        },
      });
    },
    bookmark(bookmarked) {
      const slug = this.module.slug;
      this.$apollo.mutate({
        mutation: UPDATE_MODULE_BOOKMARK_MUTATION,
        variables: {
          input: {
            module: slug,
            bookmarked,
          },
        },
        update: (store) => {
          const fragment = MODULE_FRAGMENT;
          const id = store.identify({
            __typename: 'ModuleNode',
            slug: slug,
          });

          const fragmentName = 'ModuleLegacyParts';
          const module = store.readFragment({
            fragment,
            id,
            fragmentName,
          });

          let bookmark;

          if (bookmarked) {
            bookmark = {
              __typename: 'ModuleBookmarkNode',
              note: null,
            };
          } else {
            bookmark = null;
          }

          const data = {
            ...module,
            bookmark,
          };

          store.writeFragment({
            data,
            fragment,
            fragmentName,
            id,
          });
        },
        optimisticResponse: {
          __typename: 'Mutation',
          updateModuleBookmark: {
            __typename: 'UpdateModuleBookmarkPayload',
            success: true,
          },
        },
      });
    },
    addNote(id) {
      this.$store.dispatch('addNote', {
        content: id,
        parent: this.module.slug,
        type: 'module',
      });
    },
    editNote() {
      this.$store.dispatch('editNote', this.module.bookmark.note);
    },
    scrollTo() {
      if (this.scrollPosition && this.scrollPosition.scrollTo) {
        let options = {
          container: 'body',
          easing: 'ease',
          offset: -60,
          x: false,
          y: true,
        };
        setTimeout(() => {
          this.$scrollTo(`[data-scrollto="${this.scrollPosition.scrollTo}"]`, 1000, options);
          this.$apollo.mutate({
            mutation: SCROLL_TO_MUTATION,
            variables: {
              scrollTo: '',
            },
          });
        }, 250); // unfortunately this timeout is needed as it is hard to tell when everything is rendered
      }
    },
  },
};
</script>
