<template>
  <layout-text v-if="doc.id">
    <template v-slot:header>
      <toolbar-laptop
        :doc-id="doc.id"
        :enable-auto-labeling.sync="enableAutoLabeling"
        :guideline-text="project.guideline"
        :is-reviewd="doc.isApproved"
        :show-approve-button="project.permitApprove"
        :total="docs.count"
        class="d-none d-sm-block"
        @click:clear-label="clear"
        @click:review="approve"
      />
      <toolbar-mobile
        :total="docs.count"
        class="d-flex d-sm-none"
      />
    </template>
    <template v-slot:content>
      <v-card>
        <v-card-text class="title">
          <entity-item-box
            :labels="labels"
            :link-types="linkTypes"
            :text="doc.text"
            :entities="annotations"
            :delete-annotation="remove"
            :update-entity="update"
            :add-entity="add"
            :source-chunk="sourceChunk"
            :source-link-type="sourceLinkType"
            :select-source="selectSource"
            :select-target="selectTarget"
            :delete-link="deleteLink"
            :select-new-link-type="selectNewLinkType"
            :hide-all-link-menus="hideAllLinkMenus"
          />
        </v-card-text>
      </v-card>
    </template>
    <template v-slot:sidebar>
      <list-metadata :metadata="doc.meta" />
    </template>
  </layout-text>
</template>

<script>
import _ from 'lodash'
import {mapGetters} from 'vuex'
import LayoutText from '@/components/tasks/layout/LayoutText'
import ListMetadata from '@/components/tasks/metadata/ListMetadata'
import ToolbarLaptop from '@/components/tasks/toolbar/ToolbarLaptop'
import ToolbarMobile from '@/components/tasks/toolbar/ToolbarMobile'
import EntityItemBox from '~/components/tasks/sequenceLabeling/EntityItemBox'

const NONE = {
  id: -1,
  none: true
};

export default {
  layout: 'workspace',

  components: {
    EntityItemBox,
    LayoutText,
    ListMetadata,
    ToolbarLaptop,
    ToolbarMobile
  },

  async fetch() {
    this.docs = await this.$services.example.fetchOne(
      this.projectId,
      this.$route.query.page,
      this.$route.query.q,
      this.$route.query.isChecked,
      this.project.filterOption
    )
    const doc = this.docs.items[0]
    if (this.enableAutoLabeling) {
      await this.autoLabel(doc.id)
    }
    await this.list(doc.id)
  },

  data() {
    return {
      annotations: [],
      docs: [],
      labels: [],
      links: [],
      linkTypes: [],
      project: {},
      enableAutoLabeling: false,
      sourceChunk: NONE,
      sourceLink: NONE,
      sourceLinkType: NONE
    }
  },

  computed: {
    ...mapGetters('auth', ['isAuthenticated', 'getUsername', 'getUserId']),

    shortKeys() {
      return Object.fromEntries(this.labels.map(item => [item.id, [item.suffixKey]]))
    },
    projectId() {
      return this.$route.params.id
    },
    doc() {
      if (_.isEmpty(this.docs) || this.docs.items.length === 0) {
        return {}
      } else {
        return this.docs.items[0]
      }
    }
  },

  watch: {
    '$route.query': '$fetch',
    enableAutoLabeling(val) {
      if (val) {
        this.list(this.doc.id)
      }
    }
  },

  async created() {
    this.labels = await this.$services.label.list(this.projectId)

    this.linkTypes = await this.$services.linkTypes.list(this.projectId)

    this.project = await this.$services.project.findById(this.projectId)
  },

  methods: {
    async list(docId) {
      this.hideAllLinkMenus();

      const annotations = await this.$services.sequenceLabeling.list(this.projectId, docId);
      const links = await this.$services.sequenceLabeling.listLinks(this.projectId);

      annotations.forEach(function(annotation) {
        annotation.links = links.filter(link => link.annotation_id_1 === annotation.id);
      });

      this.annotations = annotations;
      this.links = links;
    },

    populateLinks() {
      const links = this.links;
      this.annotations.forEach(function(annotation) {
        annotation.links = links.filter(link => link.annotation_id_1 === annotation.id);
      });
    },

    async remove(id) {
      this.hideAllLinkMenus();
      await this.$services.sequenceLabeling.delete(this.projectId, this.doc.id, id)
      await this.list(this.doc.id)
    },

    async add(startOffset, endOffset, labelId) {
      this.hideAllLinkMenus();
      await this.$services.sequenceLabeling.create(this.projectId, this.doc.id, labelId, startOffset, endOffset)
      await this.list(this.doc.id)
    },

    async update(labelId, annotationId) {
      this.hideAllLinkMenus();
      await this.$services.sequenceLabeling.changeLabel(this.projectId, this.doc.id, annotationId, labelId)
      await this.list(this.doc.id)
    },

    async clear() {
      await this.$services.sequenceLabeling.clear(this.projectId, this.doc.id)
      await this.list(this.doc.id)
    },

    async autoLabel(docId) {
      try {
        await this.$services.sequenceLabeling.autoLabel(this.projectId, docId)
      } catch (e) {
        console.log(e.response.data.detail)
      }
    },

    async approve() {
      const approved = !this.doc.isApproved
      await this.$services.example.approve(this.projectId, this.doc.id, approved)
      await this.$fetch()
    },

    selectSource(chunk) {
      this.sourceChunk = chunk;
    },

    async selectTarget(chunk) {
      // to avoid duplicated links:
      if (!chunk.links.find(ch => ch.id === this.sourceChunk.id)) {
        await this.$services.sequenceLabeling.createLink(this.projectId, this.sourceChunk.id, chunk.id, this.sourceLinkType.id, this.getUserId);
        await this.list(this.doc.id);
      }
      this.hideAllLinkMenus();
    },

    async deleteLink(id, ndx) {
      await this.$services.sequenceLabeling.deleteLink(this.projectId, this.sourceChunk.links[ndx].id)
      await this.list(this.doc.id)

      this.hideAllLinkMenus();
    },

    selectNewLinkType(type) {
      this.sourceLinkType = type;
    },

    hideAllLinkMenus() {
      this.sourceChunk = NONE;
      this.sourceLinkType = NONE;
    }
  },

  validate({ params, query }) {
    return /^\d+$/.test(params.id) && /^\d+$/.test(query.page)
  }
}
</script>
