import * as marked from 'marked';
import VueJsonPretty from 'vue-json-pretty';
import isEmpty from 'lodash.isempty';
import HTTP from './http';
import Preview from './preview.vue';

const getOffsetFromUrl = (url) => {
  const offsetMatch = url.match(/[?#].*offset=(\d+)/);
  if (offsetMatch == null) {
    return 0;
  }

  return parseInt(offsetMatch[1], 10);
};

const removeHost = (url) => {
  if (!url) {
    return url;
  }

  const hostMatch = url.match(/^https?:\/\/[^/]*\/(.*)$/);
  if (hostMatch == null) {
    return url;
  }

  return `${window.location.origin}/${hostMatch[1]}`;
};

const storeOffsetInUrl = (offset) => {
  let href = window.location.href;

  const fragmentStart = href.indexOf('#') + 1;
  if (fragmentStart === 0) {
    href += '#offset=' + offset;
  } else {
    const prefix = href.substring(0, fragmentStart);
    const fragment = href.substring(fragmentStart);

    const newFragment = fragment.split('&').map((fragmentPart) => {
      const keyValue = fragmentPart.split('=');
      return keyValue[0] === 'offset'
        ? 'offset=' + offset
        : fragmentPart;
    }).join('&');

    href = prefix + newFragment;
  }

  window.location.href = href;
};

const getLimitFromUrl = (url, prevLimit) => {
  try {
    const limitMatch = url.match(/[?#].*limit=(\d+)/);

    return parseInt(limitMatch[1], 10);
  } catch (err) {
    return prevLimit;
  }
};

const getSidebarTotal = (count, limit) => (
  count !== 0 && limit !== 0
    ? Math.ceil(count / limit)
    : 0
);

const getSidebarPage = (offset, limit) => (
  limit !== 0
    ? Math.ceil(offset / limit) + 1
    : 0
);

export default {
  components: { VueJsonPretty, Preview },

  data() {
    return {
      pageNumber: 0,
      docs: [],
      annotations: [],
      labels: [],
      guideline: '',
      total: 0,
      remaining: 0,
      searchQuery: '',
      url: '',
      offset: getOffsetFromUrl(window.location.href),
      picked: 'all',
      ordering: '',
      count: 0,
      prevLimit: 0,
      paginationPages: 0,
      paginationPage: 0,
      singleClassClassification: false,
      isAnnotationApprover: false,
      isMetadataActive: false,
      isAnnotationGuidelineActive: false,
    };
  },

  methods: {

    resetScrollbar() {
      const textbox = this.$refs.textbox;
      if (textbox) {
        textbox.scrollTop = 0;
      }
    },

    async nextPage() {
      this.pageNumber += 1;
      if (this.pageNumber === this.docs.length) {
        if (this.next) {
          this.url = this.next;
          await this.search();
          this.pageNumber = 0;
        } else {
          this.pageNumber = this.docs.length - 1;
        }
      } else {
        this.resetScrollbar();
      }
    },

    async prevPage() {
      this.pageNumber -= 1;
      if (this.pageNumber === -1) {
        if (this.prev) {
          this.url = this.prev;
          await this.search();
          this.pageNumber = this.docs.length - 1;
        } else {
          this.pageNumber = 0;
        }
      } else {
        this.resetScrollbar();
      }
    },

    async nextPagination() {
      if (this.next) {
        this.url = this.next;
        await this.search();
        this.pageNumber = 0;
      } else {
        this.pageNumber = this.docs.length - 1;
      }
      this.resetScrollbar();
    },

    async prevPagination() {
      if (this.prev) {
        this.url = this.prev;
        await this.search();
        this.pageNumber = this.docs.length - this.limit;
      } else {
        this.pageNumber = 0;
      }
      this.resetScrollbar();
    },

    async search() {
      await HTTP.get(this.url).then((response) => {
        this.docs = response.data.results;
        this.next = removeHost(response.data.next);
        this.prev = removeHost(response.data.previous);
        this.count = response.data.count;
        this.annotations = this.docs.map(doc => doc.annotations);
        this.offset = getOffsetFromUrl(this.url);
        this.prevLimit = this.limit;
        if (this.next || this.prevLimit) {
          this.limit = getLimitFromUrl(this.next, this.prevLimit);
        } else {
          this.limit = this.count;
        }
        this.paginationPages = getSidebarTotal(this.count, this.limit);
        this.paginationPage = getSidebarPage(this.offset, this.limit);
      });
    },

    documentMetadataFor(i) {
      const document = this.docs[i];
      if (document == null || document.meta == null) {
        return null;
      }

      const metadata = JSON.parse(document.meta);
      if (isEmpty(metadata)) {
        return null;
      }

      return metadata;
    },

    getState() {
      if (this.picked === 'all') {
        return '';
      }
      if (this.picked === 'active') {
        return 'true';
      }
      return 'false';
    },

    async submit() {
      const state = this.getState();
      this.url = `docs?q=${this.searchQuery}&is_checked=${state}&offset=${this.offset}&ordering=${this.ordering}`;
      await this.search();
      this.pageNumber = 0;
    },

    removeLabel(annotation) {
      const docId = this.docs[this.pageNumber].id;
      return HTTP.delete(`docs/${docId}/annotations/${annotation.id}`).then(() => {
        const index = this.annotations[this.pageNumber].indexOf(annotation);
        this.annotations[this.pageNumber].splice(index, 1);
      });
    },

    replaceNull(shortcut) {
      if (shortcut == null) {
        shortcut = '';
      }
      shortcut = shortcut.split(' ');
      return shortcut;
    },

    shortcutKey(label) {
      let shortcut = label.suffix_key;
      if (label.prefix_key) {
        shortcut = `${label.prefix_key} ${shortcut}`;
      }
      return shortcut;
    },

    approveDocumentAnnotations() {
      const document = this.docs[this.pageNumber];
      const approved = !this.documentAnnotationsAreApproved;

      HTTP.post(`docs/${document.id}/approve-labels`, { approved }).then((response) => {
        Object.assign(this.docs[this.pageNumber], response.data);
      });
    },

  },

  watch: {

    picked() {
      this.submit();
    },

    ordering() {
      this.offset = 0;
      this.submit();
    },

    annotations() {
      // fetch progress info.
      HTTP.get('statistics?include=total&include=remaining').then((response) => {
        this.total = response.data.total;
        this.remaining = response.data.remaining;
      });
    },

    offset() {
      storeOffsetInUrl(this.offset);
    },
  },

  created() {
    HTTP.get('labels').then((response) => {
      this.labels = response.data;
    });
    HTTP.get().then((response) => {
      this.singleClassClassification = response.data.single_class_classification;
      this.guideline = response.data.guideline;
      const roles = response.data.current_users_role;
      this.isAnnotationApprover = roles.is_annotation_approver || roles.is_project_admin;
    });
    this.submit();
  },

  computed: {
    achievement() {
      const done = this.total - this.remaining;
      const percentage = Math.round(done / this.total * 100);
      return this.total > 0 ? percentage : 0;
    },

    compiledMarkdown() {
      const documentMetadata = this.documentMetadata;

      const guideline = documentMetadata && documentMetadata.guideline
        ? documentMetadata.guideline
        : this.guideline;

      return marked(guideline, {
        sanitize: true,
      });
    },

    documentAnnotationsAreApproved() {
      const document = this.docs[this.pageNumber];
      return document != null && document.annotation_approver != null;
    },

    documentAnnotationsApprovalTooltip() {
      const document = this.docs[this.pageNumber];

      return this.documentAnnotationsAreApproved
        ? `Annotations approved by ${document.annotation_approver}, click to reject annotations`
        : 'Click to approve annotations';
    },

    displayDocumentMetadata() {
      let documentMetadata = this.documentMetadata;
      if (documentMetadata == null) {
        return null;
      }

      documentMetadata = { ...documentMetadata };
      delete documentMetadata.guideline;
      delete documentMetadata.documentSourceUrl;
      return documentMetadata;
    },

    documentMetadata() {
      return this.documentMetadataFor(this.pageNumber);
    },

    id2label() {
      const id2label = {};
      for (let i = 0; i < this.labels.length; i++) {
        const label = this.labels[i];
        id2label[label.id] = label;
      }
      return id2label;
    },

    progressColor() {
      if (this.achievement < 30) {
        return 'is-danger';
      }
      if (this.achievement < 70) {
        return 'is-warning';
      }
      return 'is-primary';
    },
  },
};