<template>
  <div class="content-block-form content-list__parent">
    <div class="content-block-form__content">
      <h1
        class="heading-1 content-block-form__heading"
        data-cy="content-block-form-heading"
      >
        {{ title }}
      </h1>

      <!-- Assignment toggle / checkbox -->
      <toggle
        :bordered="false"
        :checked="localContentBlock.isAssignment"
        class="content-block-form__task-toggle"
        label="Inhaltsblock als Auftrag formatieren"
        v-if="hasDefaultFeatures"
        @input="localContentBlock.isAssignment=$event"
      />

      <!-- Form for title of content block -->
      <content-form-section
        data-cy="content-form-title-section"
        title="Titel (Pflichtfeld)"
      >
        <input-with-label
          :value="localContentBlock.title"
          data-cy="content-block-title"
          placeholder="z.B. Auftrag 3"
          @input="localContentBlock.title=$event"
        />
      </content-form-section>

      <!-- Add content at top of content block -->
      <add-content-link
        @click="addBlock(-1)"
      />

      <!-- Loop for outer contents layer -->
      <div
        class="content-list content-list--creator content-block-form__segment"
        v-for="(block, outer) in localContentBlock.contents"
        :key="block.id"
      >
        <!-- If the block is a content list -->
        <div
          class="content-block-form__segment"
          data-cy="content-list"
          v-if="block.type === 'content_list_item'"
        >
          <content-element-actions
            class="content-block-form__actions"
            :actions="{extended: true, up: outer>0, down: outer<localContentBlock.contents.length }"
            @remove="remove(outer)"
            @move-up="up(outer)"
            @move-down="down(outer)"
            @move-top="top(outer)"
            @move-bottom="bottom(outer)"
          />
          <ol
            class="content-list__item"
            data-cy="content-list-item"
          >
            <li
              class="content-block-form__segment"
              v-for="(content, index) in block.contents"
              :key="content.id"
            >
              <content-element
                :first-element="index===0"
                :last-element="index===block.contents.length-1"
                :element="content"
                class="content-block-form__segment"
                :top-level="false"
                @update="update(index, $event, outer)"
                @remove="remove(outer, index, $event)"
                @up="up(outer, index)"
                @down="down(outer, index)"
                @top="top(outer, index)"
                @bottom="bottom(outer, index)"
              />

              <add-content-link
                class="content-block-form__add-button"
                @click="addBlock(outer, index)"
              />
            </li>
          </ol>
        </div>

        <!-- If the block is a single element -->
        <content-element
          :element="block"
          class="content-block-form__segment"
          :top-level="true"
          :first-element="outer===0"
          :last-element="outer===localContentBlock.contents.length-1"
          v-else
          @update="update(outer, $event)"
          @remove="remove(outer, undefined, $event)"
          @up="up(outer)"
          @down="down(outer)"
          @top="top(outer)"
          @bottom="bottom(outer)"
        />

        <!-- Add element after the looped item -->
        <add-content-link
          @click="addBlock(outer)"
        />
      </div>
    </div><!-- -->
    <!-- Save and Cancel buttons -->
    <footer class="content-block-form__footer">
      <div class="content-block-form__buttons">
        <button
          :disabled="!isValid"
          class="button button--primary"
          data-cy="save-button"
          @click="save(localContentBlock)"
        >
          Speichern
        </button>
        <a
          class="button"
          @click="$emit('back')"
        >Abbrechen</a>
      </div>
    </footer>
  </div>
</template>

<script lang="ts">
  import Vue, {PropType} from 'vue';
  import Toggle from '@/components/ui/Toggle.vue';
  import ContentFormSection from '@/components/content-block-form/ContentFormSection.vue';
  import InputWithLabel from '@/components/ui/InputWithLabel.vue';
  import AddContentLink from '@/components/content-block-form/AddContentLink.vue';

  import ContentElement from '@/components/content-block-form/ContentElement.vue';
  import {moveToIndex, removeAtIndex, replaceAtIndex, swapElements} from '@/graphql/immutable-operations';

  import {CHOOSER, transformInnerContents} from '@/components/content-block-form/helpers.js';
  import ContentElementActions from '@/components/content-block-form/ContentElementActions.vue';
  import {ContentBlock, numberOrUndefined} from "@/@types";
  import {DEFAULT_FEATURE_SET} from "@/consts/features.consts";

  // TODO: refactor this file, it's huuuuuge!
  interface ContentBlockFormData {
   localContentBlock: any;
  }

  export default Vue.extend({
    props: {
      title: {
        type: String,
        default: '',
      },
      contentBlock: {
        type: Object as PropType<ContentBlock>,
        required: true,
      },
      features: {
        type: String,
        default: DEFAULT_FEATURE_SET
      }
    },
    provide(): object {
      return {
        features: this.features
      };
    },
    components: {
      ContentElementActions,
      ContentElement,
      AddContentLink,
      InputWithLabel,
      ContentFormSection,
      Toggle,
    },
    data(): ContentBlockFormData {
      return {
        localContentBlock: Object.assign({}, {
          title: this.contentBlock.title,
          // contents: [...this.contentBlock.contents],
          contents: transformInnerContents([...this.contentBlock.contents]),
          id: this.contentBlock.id || undefined,
          isAssignment: this.contentBlock.type && this.contentBlock.type.toLowerCase() === 'task',
        }),
      };
    },
    computed: {
      isValid(): boolean {
        return this.localContentBlock.title > '';
      },
      hasDefaultFeatures(): boolean {
        return this.features === DEFAULT_FEATURE_SET;
      }
    },
    methods: {
      update(index: number, element: any, parent?: number) {
        if (parent === undefined) {
          // element is top level
          this.localContentBlock.contents = [
            ...this.localContentBlock.contents.slice(0, index),
            element,
            ...this.localContentBlock.contents.slice(index + 1),
          ];
        } else {
          const parentBlock = this.localContentBlock.contents[parent];

          this.localContentBlock.contents = [
            ...this.localContentBlock.contents.slice(0, parent),
            {
              ...parentBlock,
              contents: [
                ...parentBlock.contents.slice(0, index),
                element,
                ...parentBlock.contents.slice(index + 1),
              ],
            },
            ...this.localContentBlock.contents.slice(parent + 1),
          ];
        }
      },
      addBlock(afterOuterIndex: number, innerIndex?: number) {
        if (innerIndex !== undefined) {
          const block = this.localContentBlock.contents[afterOuterIndex];
          this.localContentBlock.contents = [
            ...this.localContentBlock.contents.slice(0, afterOuterIndex),
            {
              ...block,
              contents: [
                ...block.contents.slice(0, innerIndex + 1),
                {
                  id: -1,
                  type: CHOOSER,
                },
                ...block.contents.slice(innerIndex + 1),
              ],
            },
            ...this.localContentBlock.contents.slice(afterOuterIndex + 1),
          ];
        } else {
          this.localContentBlock.contents = [
            ...this.localContentBlock.contents.slice(0, afterOuterIndex + 1),
            {
              id: -1,
              type: CHOOSER,
              includeListOption: true,
            },
            ...this.localContentBlock.contents.slice(afterOuterIndex + 1),
          ];
        }
      },
      remove(outer: number, inner?: number, askForConfirmation = true) {
        if(askForConfirmation) {
          this.$modal.open('confirm')
            .then(() => {
              this.executeRemoval(outer, inner);
            })
            .catch(() => {

            });
        } else {
          this.executeRemoval(outer, inner);
        }
      },
      shift(outer: number, inner: numberOrUndefined = undefined, distance: number) {
        if (inner === undefined) {
          this.localContentBlock.contents = swapElements(this.localContentBlock.contents, outer, outer + distance);
        } else {
          const {contents} = this.localContentBlock;
          const outerElement = contents[outer];
          const newOuterElement = {
            ...outerElement,
            contents: swapElements(outerElement.contents, inner, inner + distance),
          };
          this.localContentBlock.contents = replaceAtIndex(contents, outer, newOuterElement);
        }
      },
      top(outer: number, inner: numberOrUndefined = undefined) {
        if (inner === undefined) {
          this.localContentBlock.contents = moveToIndex(this.localContentBlock.contents, outer, 0);
        } else {
          const {contents} = this.localContentBlock;
          const outerElement = contents[outer];
          const newOuterElement = {
            ...outerElement,
            contents: moveToIndex(outerElement.contents, inner, 0),
          };
          this.localContentBlock.contents = replaceAtIndex(contents, outer, newOuterElement);
        }
      },
      up(outer: number, inner: numberOrUndefined = undefined) {
        this.shift(outer, inner, -1);
      },
      down(outer: number, inner: numberOrUndefined = undefined) {
        this.shift(outer, inner, 1);
      },
      bottom(outer: number, inner: numberOrUndefined = undefined) {
        if (inner === undefined) {
          const maxIndex = this.localContentBlock.contents.length - 1;
          this.localContentBlock.contents = moveToIndex(this.localContentBlock.contents, outer, maxIndex);
        } else {
          const {contents} = this.localContentBlock;
          const outerElement = contents[outer];
          const maxIndex = outerElement.contents.length - 1;
          const newOuterElement = {
            ...outerElement,
            contents: moveToIndex(outerElement.contents, inner, maxIndex),
          };
          this.localContentBlock.contents = replaceAtIndex(contents, outer, newOuterElement);
        }
      },
      executeRemoval(outer: number, inner: numberOrUndefined = undefined) {
        if (inner === undefined) {
          // not a list item container, just remove the element from the outer array
          this.localContentBlock.contents = removeAtIndex(this.localContentBlock.contents, outer);
        } else {
          let prevInnerContents = this.localContentBlock.contents[outer].contents;
          let innerContents = removeAtIndex(prevInnerContents, inner);

          if (innerContents.length) {
            /*
              there is still an element inside the outer element after removal,
              so we replace the previous element in the outer array with the new one with fewer contents
             */
            let element = {
              ...this.localContentBlock.contents[outer],
              contents: innerContents,
            };
            this.localContentBlock.contents = replaceAtIndex(this.localContentBlock.contents, outer, element);
          } else {
            // inner contents is now empty, remove the whole element from the outer array
            this.localContentBlock.contents = removeAtIndex(this.localContentBlock.contents, outer);
          }
        }
      },
      save(contentBlock: ContentBlock) {
        this.$emit('save', contentBlock);
      },
    },

  });
</script>

<style lang="scss">
  @import '~styles/helpers';
  // override parent page properties
  .layout--no-scroll {
    padding-bottom: 20px;
    height: 100vh;
    overflow-y: hidden;
    box-sizing: border-box;

    .module-page {
      height: 100vh;
      grid-template-rows: 60px 1fr;
      padding-bottom: $small-spacing;
      box-sizing: border-box;
    }
  }
</style>

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

  .content-block-form {
    max-width: 100%;
    display: grid;
    grid-template-columns: 100vw;
    grid-template-rows:  85vh 80px;
    height: 100vh;
    grid-template-areas:
      'content'
      'footer';

    @media (-webkit-min-device-pixel-ratio: 1.25) {
      grid-template-rows:  80vh auto;
      height: auto;
    }


    &__heading {
      @include heading-1;
    }

    &__task-toggle {
      margin-bottom: $large-spacing;
    }

    &__add-button {
    }

    &__segment {
      display: flex;
      flex-direction: column;
      align-items: stretch;

      margin-bottom: $large-spacing;

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

    &__actions {
      align-self: flex-end;
    }

    &__content {
      grid-area: content;
      overflow-x: visible;
      overflow-y: auto;
      padding: 10px;
      align-items: center;
      display: flex;
      flex-direction: column;

      & > * { // we make an exception and use a wildcard here
        width: 800px;
        max-width: 100vw;
        box-sizing: border-box;
      }
    }

    &__footer {
      padding: $medium-spacing 0;
      border-top: 1px solid $color-silver;
      margin-top: auto;
      grid-area: footer;
      justify-content: center;
      display: flex;
    }

    &__buttons {
      width: 800px;
    }
  }
</style>
