<template>
  <div>
    <section class="section">
      <SearchForm :effects="effects" :uses="uses" :conditions="conditions" :flavors="flavors" />
    </section>
    <section class="section">
      <StrainList :strains="matches" />
    </section>
  </div>
</template>

<script>
import lunr from 'lunr';
import SearchForm from '../components/SearchForm.vue';
import StrainList from '../components/StrainList.vue';
import data from '../../../scraper/db.json';
import emitter from '../lib/emitter.mjs';
import store from '../lib/store.mjs';

export default {
  name: 'Home',
  components: {
    SearchForm,
    StrainList,
  },
  head: {
    title: 'Strain Search',
    link: [
      {
        rel: 'stylesheet',
        href: 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css',
      },
    ],
  },
  data() {
    return {
      ...data,
      matches: [],
      requirements: {
        name: '',
        effects: [],
        uses: [],
        conditions: [],
        flavors: [],
      },
    };
  },
  computed: {
    hasName() {
      return this.requirements.name.length > 0;
    },
    hasFilters() {
      return (
        this.requirements.effects.length > 0 ||
        this.requirements.uses.length > 0 ||
        this.requirements.conditions.length > 0 ||
        this.requirements.flavors.length > 0
      );
    },
    searchParams() {
      const searchParts = [this.requirements.name];
      this.requirements.effects.forEach(t => searchParts.push(`+effects:${t}`));
      this.requirements.uses.forEach(t => searchParts.push(`+uses:${t}`));
      this.requirements.conditions.forEach(t => searchParts.push(`+conditions:${t}`));
      this.requirements.flavors.forEach(t => searchParts.push(`+flavors:${t}`));

      return searchParts.join(' ');
    },
  },
  methods: {
    showDefaults(limit = 40) {
      // const favs = store.get('favorites') || [];
      // const favStrains = this.strains.filter(({ id }) => favs.indexOf(id) !== -1);
      // this.matches = favStrains.concat(this.strains.slice(0, limit - favStrains.length));

      this.matches = this.strains.slice(0, limit);
    },
    updateMatches(limit = 40) {
      if (!this.hasName && !this.hasFilters) {
        this.showDefaults(limit);
        return;
      }

      try {
        const hits = this.idx.search(this.searchParams);
        // .slice(0, limit);
        const refs = hits.map(({ ref }) => parseInt(ref, 10));

        this.matches = this.strains
          .map(strain => {
            const idx = refs.indexOf(strain.id);
            if (idx < 0) return null;
            return Object.assign({ score: hits[idx].score }, strain);
          })
          .filter(Boolean)
          .sort((a, b) => {
            if (a.score === b.score) {
              // sort matching search score by adjusted rating
              if (a.rating_adjusted === b.rating_adjusted) return 0;
              return a.rating_adjusted > b.rating_adjusted ? -1 : 1;
            }
            return a.score > b.score ? -1 : 1;
          });
      } catch (err) {
        this.matches = [];
        emitter.emit('error', err.message);
      }
    },
  },
  created() {
    // lunr setup
    this.idx = lunr(function lunrSetup() {
      this.ref('id');
      this.field('name');
      this.field('effects');
      this.field('uses');
      this.field('conditions');
      this.field('flavors');
      data.strains.forEach(doc => this.add(doc));
    });

    // function to handle search form submissions
    this.searchListener = reqs => {
      this.requirements = reqs;
      this.updateMatches();
    };

    // listen for search form submissions
    emitter.on('search', r => this.searchListener(r));

    // listen for favorite changes
    emitter.on('favorite', ({ id, isFav }) => {
      const favs = store.get('favorites') || [];
      const idx = favs.indexOf(id);

      // remove previously favorited strain
      if (idx >= 0 && !isFav) {
        store.set('favorites', favs.filter(f => f !== id));
      } else if (idx === -1 && isFav) {
        store.set('favorites', favs.concat(id));
      }
    });
    this.updateMatches(); // set initial match list
  },
  beforeDestroy() {
    emitter.off('search', r => this.searchListener(r));
  },
};
</script>
