import _ from 'lodash';

import { RECEIVE_ANNOTATIONS, RECEIVE_MESSAGES_COUNT } from '../actions';
import { isDefinitionInTags } from '../utils';

/**
 * termsMap is a mapping { term: [annotations,...] }
 * where annotation
 */
function getDefinitionsAndReferences(annotations, termsMap) {
  return Object.keys(termsMap).reduce((res, term) => {
    res[term] = res[term] || {
      keywordAnnotations: termsMap[term],
      definitions: [],
      references: [],
    };

    termsMap[term].forEach((annotation) => {
      const annotationText = (annotation.text && annotation.text.trim()) || '';
      const tags = annotation.tags.map(t => t.toLowerCase());
      if (annotationText && isDefinitionInTags(tags)) {
        const annotationObj = annotation;
        annotationObj.isPersonal = true;
        res[term].definitions.push(annotationObj);
      }
    });

    annotations.forEach((annotation) => {
      const tags = annotation.tags.map(t => t.toLowerCase());
      if (isDefinitionInTags(tags) && tags.includes(term.toLowerCase())) {
        const annotationObj = annotation;
        annotationObj.isPersonal = false;
        res[term].definitions.push(annotationObj);
      } else {
        let exactText;

        (annotation.target[0].selector || []).some((selector) => {
          if (selector.type === 'TextQuoteSelector' && selector.exact) {
            exactText = selector.exact.trim().toLowerCase();
            return true;
          }
          return false;
        });

        if (exactText && exactText.includes(term.toLowerCase()) && !tags.includes('cat:mot-clef')) {
          res[term].references.push(annotation);
        }
      }
    });
    return res;
  }, {});
}

/**
 * Calculate stats on terms
 */
function addTermStats(termsMap) {
  return _.reduce(
    termsMap,
    (res, termDef, term) => {
      res[term] = _.assign({
        definitionsNb: (termDef.definitions || []).length,
        referenceNb: (termDef.references || []).length,
      }, termDef);
      return res;
    },
    {},
  );
}


function terms(
  state = {
  },
  action,
) {
  switch (action.type) {
    case RECEIVE_ANNOTATIONS: {
      const { annotations } = action;
      // let termsMap = getTerms(annotations);
      let termsMap = action.terms;
      termsMap = getDefinitionsAndReferences(annotations, termsMap);
      return Object.assign({}, state, addTermStats(termsMap));
    }
    case RECEIVE_MESSAGES_COUNT: {
      const { terms: termList, messagesCount: counts } = action;
      const termCountMap = _.zipObject(termList, counts);

      return Object.assign({}, state, _.mapValues(
        state,
        (termDef, term) => Object.assign(
          {},
          termDef,
          { messagesCount: termCountMap[term] || 0 },
        ),
      ));
    }
    default:
      return state;
  }
}

export default terms;
