<template>
  <div
    :class="{ 'hideable-element--greyed-out': hidden }"
    class="content-block__container hideable-element content-list__parent"
  >
    <div :class="specialClass" :style="instrumentStyle" class="content-block" data-cy="content-block">
      <div class="block-actions" v-if="canEditModule && !isInstrumentBlock">
        <user-widget v-bind="me" class="block-actions__user-widget content-block__user-widget" v-if="isMine" />
        <more-options-widget>
          <li class="popover-links__link" v-if="!isInstrumentBlock">
            <popover-link
              data-cy="duplicate-content-block-link"
              text="Duplizieren"
              @link-action="duplicateContentBlock(contentBlock)"
            />
          </li>
          <li class="popover-links__link" v-if="isMine">
            <popover-link
              data-cy="delete-content-block-link"
              text="Löschen"
              @link-action="deleteContentBlock(contentBlock)"
            />
          </li>

          <li class="popover-links__link" v-if="isMine">
            <popover-link text="Bearbeiten" @link-action="editContentBlock(contentBlock)" />
          </li>
        </more-options-widget>
      </div>
      <div class="content-block__visibility">
        <visibility-action :block="contentBlock" v-if="canEditModule" />
      </div>

      <h3
        class="content-block__instrument-label"
        data-cy="instrument-label"
        :style="instrumentLabelStyle"
        v-if="instrumentLabel !== ''"
      >
        {{ instrumentLabel }}
      </h3>
      <h4 class="content-block__title" v-if="!contentBlock.indent">
        {{ contentBlock.title }}
      </h4>

      <content-component
        :component="component"
        :root="root"
        :parent="contentBlock"
        :bookmarks="contentBlock.bookmarks"
        :notes="contentBlock.notes"
        :edit-mode="editMode"
        v-for="component in contentBlocksWithContentLists.contents"
        :key="component.id"
      />
    </div>

    <add-content-button :where="{ after: contentBlock }" v-if="canEditModule" />
  </div>
</template>

<script>
import AddContentButton from '@/components/AddContentButton';
import MoreOptionsWidget from '@/components/MoreOptionsWidget';
import UserWidget from '@/components/UserWidget';
import VisibilityAction from '@/components/visibility/VisibilityAction';

import CHAPTER_QUERY from '@/graphql/gql/queries/chapterQuery.gql';
import DELETE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/deleteContentBlock.gql';
import DUPLICATE_CONTENT_BLOCK_MUTATION from '@/graphql/gql/mutations/duplicateContentBlock.gql';

import me from '@/mixins/me';

import { hidden } from '@/helpers/visibility';
import { CONTENT_TYPE } from '@/consts/types';
import PopoverLink from '@/components/ui/PopoverLink';
import { insertAtIndex, removeAtIndex } from '@/graphql/immutable-operations';
import { EDIT_CONTENT_BLOCK_PAGE } from '@/router/module.names';
import { instrumentCategory } from '@/helpers/instrumentType';

const ContentComponent = () =>
  import(/* webpackChunkName: "content-components" */ '@/components/content-blocks/ContentComponent');

export default {
  name: 'ContentBlock',
  props: {
    contentBlock: {
      type: Object,
      default: () => ({}),
    },
    parent: {
      type: Object,
      default: () => ({}),
    },
    editMode: {
      type: Boolean,
      default: true,
    },
  },

  mixins: [me],

  components: {
    PopoverLink,
    ContentComponent,
    AddContentButton,
    VisibilityAction,
    MoreOptionsWidget,
    UserWidget,
  },

  computed: {
    canEditModule() {
      return !this.contentBlock.indent && this.editMode;
    },
    specialClass() {
      return `content-block--${this.contentBlock.type.toLowerCase()}`;
    },
    isInstrumentBlock() {
      return !!this.contentBlock.instrumentCategory;
    },
    // todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
    instrumentStyle() {
      if (this.isInstrumentBlock) {
        return {
          backgroundColor: this.contentBlock.instrumentCategory.background,
        };
      }
      return {};
    },
    instrumentLabel() {
      const contentType = this.contentBlock.type.toLowerCase();
      if (contentType.startsWith('base')) {
        // all legacy instruments start with `base`
        return instrumentCategory(contentType);
      }
      if (this.isInstrumentBlock) {
        return instrumentCategory(this.contentBlock.instrumentCategory.name);
      }
      return '';
    },
    // todo: use dynamic css class with v-bind once we're on Vue 3: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
    instrumentLabelStyle() {
      if (this.isInstrumentBlock) {
        return {
          color: this.contentBlock.instrumentCategory.foreground,
        };
      }
      return {};
    },
    canEditContentBlock() {
      return this.isMine && !this.contentBlock.indent;
    },
    isMine() {
      return this.contentBlock.mine;
    },
    contentBlocksWithContentLists() {
      /*
        collects all content_list_items in content_lists:
        {
          text_block,
          content_list_item: [contents...],
          content_list_item: [contents...],
          text_block
        } becomes
        {
          text_block,
          content_list: [content_list_item: [contents...], content_list_item: [contents...]],
          text_block
        }
        */
      let contentList = [];
      let newContent = this.contentBlock.contents.reduce((newContents, content, index) => {
        // collect content_list_items
        if (content.type === 'content_list_item') {
          contentList = [...contentList, content];
          if (index === this.contentBlock.contents.length - 1) {
            // content is last element of contents array
            let updatedContent = [...newContents, ...this.createContentListOrBlocks(contentList)];
            return updatedContent;
          }
          return newContents;
        } else {
          // handle all other items and reset current content_list if necessary
          if (contentList.length !== 0) {
            newContents = [...newContents, ...this.createContentListOrBlocks(contentList), content];
            contentList = [];
            return newContents;
          } else {
            return [...newContents, content];
          }
        }
      }, []);
      return Object.assign({}, this.contentBlock, {
        contents: newContent,
      });
    },
    hidden() {
      return hidden({
        block: this.contentBlock,
        schoolClass: this.schoolClass,
        type: CONTENT_TYPE,
      });
    },
    root() {
      // we need the root content block id, not the generated content block if inside a content list block
      return this.contentBlock.root ? this.contentBlock.root : this.contentBlock.id;
    },
  },
  methods: {
    duplicateContentBlock({ id }) {
      const parent = this.parent;
      this.$apollo.mutate({
        mutation: DUPLICATE_CONTENT_BLOCK_MUTATION,
        variables: {
          input: {
            id,
          },
        },
        update(
          store,
          {
            data: {
              duplicateContentBlock: { contentBlock },
            },
          }
        ) {
          if (contentBlock) {
            const query = CHAPTER_QUERY;
            const variables = {
              id: parent.id,
            };
            const { chapter } = store.readQuery({ query, variables });
            const index = chapter.contentBlocks.findIndex((contentBlock) => contentBlock.id === id);
            const contentBlocks = insertAtIndex(chapter.contentBlocks, index, contentBlock);
            const data = {
              chapter: {
                ...chapter,
                contentBlocks,
              },
            };
            store.writeQuery({ query, variables, data });
          }
        },
      });
    },
    editContentBlock(contentBlock) {
      const route = {
        name: EDIT_CONTENT_BLOCK_PAGE,
        params: {
          id: contentBlock.id,
        },
      };
      this.$router.push(route);
    },
    deleteContentBlock(contentBlock) {
      this.$modal
        .open('confirm')
        .then(() => {
          this.doDeleteContentBlock(contentBlock);
        })
        .catch();
    },
    doDeleteContentBlock(contentBlock) {
      const parent = this.parent;
      const id = contentBlock.id;
      this.$apollo.mutate({
        mutation: DELETE_CONTENT_BLOCK_MUTATION,
        variables: {
          input: {
            id,
          },
        },
        update(
          store,
          {
            data: {
              deleteContentBlock: { success },
            },
          }
        ) {
          if (success) {
            const query = CHAPTER_QUERY;
            const variables = {
              id: parent.id,
            };
            const { chapter } = store.readQuery({ query, variables });
            const index = chapter.contentBlocks.findIndex((contentBlock) => contentBlock.id === id);
            const contentBlocks = removeAtIndex(chapter.contentBlocks, index);
            const data = {
              chapter: {
                ...chapter,
                contentBlocks,
              },
            };
            store.writeQuery({ query, variables, data });
          }
        },
      });
    },
    createContentListOrBlocks(contentList) {
      return [
        {
          type: 'content_list',
          contents: contentList,
          id: contentList[0].id,
        },
      ];
    },
  },
};
</script>

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

.content-block {
  margin-bottom: $section-spacing;
  position: relative;

  &__container {
    position: relative;
  }

  &__title {
    line-height: 1.5;
    margin-top: -0.5rem; // to offset the 1.5 line height, it leaves a padding on top
  }

  &__instrument-label {
    margin-bottom: $medium-spacing;
    @include regular-text();
  }

  &__action-button {
    cursor: pointer;
  }

  &__user-widget {
    margin-right: 0;
  }

  &--base_communication {
    @include content-box($color-accent-1-list);

    .content-block__instrument-label {
      color: $color-accent-1-dark;
    }
  }

  &--task {
    @include light-border(bottom);

    .content-block__title {
      color: $color-brand;
      margin-top: $default-padding;
      margin-bottom: $large-spacing;
      @include light-border(bottom);

      @include desktop {
        margin-top: 0;
      }
    }
  }

  &--base_society {
    @include content-box($color-accent-2-list);

    .content-block__instrument-label {
      color: $color-accent-2-dark;
    }
  }

  &--base_interdisciplinary {
    @include content-box($color-accent-4-list);

    .content-block__instrument-label {
      color: $color-accent-4-dark;
    }
  }

  &--instrument {
    @include content-box-base;
  }

  :deep(p) {
    line-height: 1.5;
    margin-bottom: 1em;

    &:last-child {
      margin-bottom: 0;
    }
  }

  :deep(.text-block) {
    ul {
      @include list-parent;
    }

    li {
      @include list-child;
      line-height: 1.5;
    }
  }
}
</style>
