<template>
  <div class="fourteen wide column">
    <div
      id="feature-list-container"
      class="ui grid mobile-column"
    >
      <div class="four wide column mobile-fullwidth">
        <h1>Signalements</h1>
      </div>
      <div class="twelve-wide column no-padding-mobile mobile-fullwidth">
        <div class="ui large text loader">
          Chargement
        </div>
        <div class="ui secondary menu no-margin">
          <a
            :class="['item no-margin', { active: showMap }]"
            data-tab="map"
            data-tooltip="Carte"
            @click="showMap = true"
          ><i class="map fitted icon" /></a>
          <a
            :class="['item no-margin', { active: !showMap }]"
            data-tab="list"
            data-tooltip="Liste"
            @click="showMap = false"
          ><i class="list fitted icon" /></a>
          <div class="item">
            <h4>
              {{ featuresCount }} signalement{{ featuresCount > 1 ? "s" : "" }}
            </h4>
          </div>

          <div
            v-if="
              project &&
                feature_types.length > 0 &&
                permissions.can_create_feature
            "
            id="button-dropdown"
            class="item right"
          >
            <div
              class="ui dropdown button compact button-hover-green"
              data-tooltip="Ajouter un signalement"
              data-position="bottom right"
              @click="toggleAddFeature"
            >
              <i class="plus fitted icon" />
              <div
                v-if="showAddFeature"
                class="menu left transition visible"
                style="z-index: 9999"
              >
                <div class="header">
                  Ajouter un signalement du type
                </div>
                <div class="scrolling menu text-wrap">
                  <router-link
                    v-for="(type, index) in feature_types"
                    :key="type.slug + index"
                    :to="{
                      name: 'ajouter-signalement',
                      params: { slug_type_signal: type.slug },
                    }"
                    class="item"
                  >
                    {{ type.title }}
                  </router-link>
                </div>
              </div>
            </div>

            <div
              v-if="checkedFeatures.length > 0 && massMode === 'modify'"
              class="ui dropdown button compact button-hover-green margin-left-25"
              data-tooltip="Modifier le statut des Signalements"
              data-position="bottom right"
              @click="toggleModifyStatus"
            >
              <i class="pencil fitted icon" />
              <div
                v-if="showModifyStatus"
                class="menu left transition visible"
                style="z-index: 9999"
              >
                <div class="header">
                  Modifier le statut des Signalements
                </div>
                <div class="scrolling menu text-wrap">
                  <span
                    v-for="status in availableStatus"
                    :key="status.value"
                    class="item"
                    @click="modifyStatus(status.value)"
                  >
                    {{ status.name }}
                  </span>
                </div>
              </div>
            </div>

            <div
              v-if="checkedFeatures.length > 0 && massMode === 'delete'"
              class="ui button compact button-hover-red margin-left-25"
              data-tooltip="Supprimer tous les signalements sélectionnés"
              data-position="bottom right"
              @click="modalAllDelete"
            >
              <i class="grey trash fitted icon" />
            </div>
          </div>
        </div>
      </div>
    </div>

    <section
      id="form-filters"
      class="ui form grid"
    >
      <div class="field wide four column no-margin-mobile">
        <label>Type</label>
        <Dropdown
          :options="featureTypeChoices"
          :selected="form.type.selected"
          :selection.sync="form.type.selected"
          :search="true"
          :clearable="true"
        />
      </div>
      <div class="field wide four column no-padding-mobile no-margin-mobile">
        <label>Statut</label>
        <!--  //* giving an object mapped on key name -->
        <Dropdown
          :options="filteredStatusChoices"
          :selected="form.status.selected.name"
          :selection.sync="form.status.selected"
          :search="true"
          :clearable="true"
        />
      </div>
      <div class="field wide four column">
        <label>Nom</label>
        <div class="ui icon input">
          <i class="search icon" />
          <div class="ui action input">
            <input
              v-model="form.title"
              type="text"
              name="title"
              @keyup.enter="resetPaginationNfetchFeatures"
            >
            <button
              id="submit-search"
              class="ui teal icon button"
              @click="resetPaginationNfetchFeatures"
            >
              <i class="search icon" />
            </button>
          </div>
        </div>
      </div>
      <!-- map params, updated on map move -->
      <input
        v-model="zoom"
        type="hidden"
        name="zoom"
      >
      <input
        v-model="lat"
        type="hidden"
        name="lat"
      >
      <input
        v-model="lng"
        type="hidden"
        name="lng"
      >
    </section>

    <div
      :class="['ui tab active map-container', {visible: showMap}]"
      data-tab="map"
    >
      <div
        id="map"
        ref="map"
      />
      <SidebarLayers v-if="basemaps && map" />
    </div>
    <FeatureListTable
      v-show="!showMap"
      :paginated-features="paginatedFeatures"
      :checked-features.sync="checkedFeatures"
      :features-count="featuresCount"
      :pagination="pagination"
      :sort="sort"
      @update:page="handlePageChange"
      @update:sort="handleSortChange"
    />

    <!-- MODAL ALL DELETE FEATURE TYPE -->
    <div
      v-if="modalAllDeleteOpen"
      class="ui dimmer modals page transition visible active"
      style="display: flex !important"
    >
      <div
        :class="[
          'ui mini modal subscription',
          { 'active visible': modalAllDeleteOpen },
        ]"
      >
        <i
          class="close icon"
          @click="modalAllDeleteOpen = false"
        />
        <div class="ui icon header">
          <i class="trash alternate icon" />
          Êtes-vous sûr de vouloir effacer
          <span v-if="checkedFeatures.length === 1"> un signalement ? </span>
          <span v-else> ces {{ checkedFeatures.length }} signalements ? </span>
        </div>
        <div class="actions">
          <button
            type="button"
            class="ui red compact fluid button"
            @click="deleteAllFeatureSelection"
          >
            Confirmer la suppression
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { mapGetters, mapState, mapActions, mapMutations } from 'vuex';
import { mapUtil } from '@/assets/js/map-util.js';
import featureAPI from '@/services/feature-api';
import SidebarLayers from '@/components/map-layers/SidebarLayers';
import FeatureListTable from '@/components/feature/FeatureListTable';
import Dropdown from '@/components/Dropdown.vue';
import axios from '@/axios-client.js';
import { allowedStatus2change } from '@/utils';

export default {
  name: 'FeatureList',

  components: {
    SidebarLayers,
    Dropdown,
    FeatureListTable,
  },

  data() {
    return {
      currentLayer: null,
      featuresCount: 0,
      form: {
        type: {
          selected: '',
        },
        status: {
          selected: '',
        },
        title: null,
      },
      lat: null,
      lng: null,
      map: null,
      modalAllDeleteOpen: false,
      next: null,
      paginatedFeatures: [],
      pagination: {
        currentPage: 1,
        pagesize: 15,
        start: 0,
        end: 15,
      },
      previous: null,
      projectSlug: this.$route.params.slug,
      showMap: true,
      showAddFeature: false,
      showModifyStatus: false,
      sort: {
        column: '',
        ascending: true,
      },
      zoom: null,
    };
  },

  computed: {
    ...mapState(['user', 'USER_LEVEL_PROJECTS']),
    ...mapGetters([
      'permissions',
    ]),
    ...mapState('projects', [
      'project',
    ]),
    ...mapState('feature', [
      'checkedFeatures',
      'clickedFeatures',
      'statusChoices',
      'massMode',
    ]),
    ...mapState('feature_type', [
      'feature_types',
    ]),
    ...mapState('map', [
      'basemaps',
    ]),

    API_BASE_URL() {
      return this.$store.state.configuration.VUE_APP_DJANGO_API_BASE;
    },

    filteredStatusChoices() {
      //* if project is not moderate, remove pending status
      return this.statusChoices.filter((el) =>
        this.project && this.project.moderation ? true : el.value !== 'pending'
      );
    },
    availableStatus() {
      if (this.project && this.user) {
        const isModerate = this.project.moderation;
        const userStatus = this.USER_LEVEL_PROJECTS[this.project.slug];
        const isOwnFeature = true; //* dans ce cas le contributeur est toujours l'auteur des signalements qu'il peut modifier
        return allowedStatus2change(this.statusChoices, isModerate, userStatus, isOwnFeature);
      }
      return [];
    },

    featureTypeChoices() {
      return this.feature_types.map((el) => el.title);
    },
  },

  watch: {
    'form.type.selected'() {
      this.resetPaginationNfetchFeatures();
    },
    'form.status.selected.value'() {
      this.resetPaginationNfetchFeatures();
    },
    map(newValue) {
      if (newValue && this.paginatedFeatures && this.paginatedFeatures.length) {
        if (this.currentLayer) {
          this.map.removeLayer(this.currentLayer);
        }
        this.currentLayer = mapUtil.addFeatures(
          this.paginatedFeatures,
          {},
          true,
          this.feature_types
        );
      }
    },
    paginatedFeatures: {
      deep: true,
      handler(newValue, oldValue) {
        if (newValue && newValue.length && newValue !== oldValue && this.map) {
          if (this.currentLayer) {
            this.map.removeLayer(this.currentLayer);
            this.currentLayer = null;
          }
          this.currentLayer = mapUtil.addFeatures(
            newValue,
            {},
            true,
            this.feature_types
          );
        } else if (newValue && newValue.length === 0) {
          if (this.currentLayer) {
            this.map.removeLayer(this.currentLayer);
            this.currentLayer = null;
          }
        }
      }
    },
  },

  mounted() {
    if (!this.project) {
      // Chargements des features et infos projet en cas d'arrivée directe sur la page ou de refresh
      this.$store.dispatch('projects/GET_PROJECT', this.projectSlug);
      this.$store
        .dispatch('projects/GET_PROJECT_INFO', this.projectSlug)
        .then(() => this.initMap());
    } else {
      this.initMap();
    }
    this.fetchPagedFeatures();
    window.addEventListener('mousedown', this.clickOutsideDropdown);
  },

  destroyed() {
    window.removeEventListener('mousedown', this.clickOutsideDropdown);
    //* allow user to change page if ever stuck on loader
    this.$store.commit('DISCARD_LOADER');
  },

  methods: {
    ...mapActions('feature', [
      'GET_PROJECT_FEATURES',
      'SEND_FEATURE'
    ]),

    ...mapMutations('feature', [
      'UPDATE_CHECKED_FEATURES'
    ]),

    toggleAddFeature() {
      this.showAddFeature = !this.showAddFeature;
      this.showModifyStatus = false;
    },

    toggleModifyStatus() {
      this.showModifyStatus = !this.showModifyStatus;
      this.showAddFeature = false;
    },

    modalAllDelete() {
      this.modalAllDeleteOpen = !this.modalAllDeleteOpen;
    },

    clickOutsideDropdown(e) {
      if (!e.target.closest('#button-dropdown')) {
        this.showModifyStatus = false;
        setTimeout(() => { //* timout necessary to give time to click on link to add feature
          this.showAddFeature = false;
        }, 500);
      }
    },

    async modifyStatus(newStatus) {
      if (this.checkedFeatures.length > 0) {
        const feature_id = this.checkedFeatures[0];
        let feature = this.clickedFeatures.find((el) => el.feature_id === feature_id);
        if (feature) {
          featureAPI.updateFeature({
            feature_id,
            feature_type__slug: feature.feature_type,
            project__slug: this.projectSlug,
            newStatus
          }).then((response) => {
            if (response && response.data && response.status === 200) {
              let newCheckedFeatures = [...this.checkedFeatures];
              newCheckedFeatures.splice(this.checkedFeatures.indexOf(response.data.id), 1);
              this.UPDATE_CHECKED_FEATURES(newCheckedFeatures);
              this.modifyStatus(newStatus);
            } else {
              this.$store.commit('DISPLAY_MESSAGE', {
                comment: `Le signalement ${feature.title} n'a pas pu être modifié`,
                level: 'negative'
              });
              this.fetchPagedFeatures();
            }
          });
        }
      } else {
        this.fetchPagedFeatures();
        this.$store.commit('DISPLAY_MESSAGE', {
          comment: 'Tous les signalements ont été modifié avec succès.',
          level: 'positive'
        });
      }
    },

    deleteFeature(feature_id) {
      const url = `${this.API_BASE_URL}features/${feature_id}/?project__slug=${this.projectSlug}`;
      axios //TODO: REFACTO -> Delete function already exist in store
        .delete(url, {})
        .then(() => {
          if (!this.modalAllDeleteOpen) {
            this.GET_PROJECT_FEATURES({
              project_slug: this.projectSlug,
            })
              .then(() => {
                this.fetchPagedFeatures();
                this.checkedFeatures.splice(feature_id);
              });
          }
        })
        .catch(() => {
          return false;
        });
    },

    deleteAllFeatureSelection() {
      let feature = {};
      this.checkedFeatures.forEach((feature_id) => {
        feature = { feature_id: feature_id }; // ? Is this usefull ?
        this.deleteFeature(feature.feature_id); //? since property feature_id is directly used after...
      });
      this.modalAllDelete();
    },

    onFilterChange() {
      if (mapUtil.getMap()) {
        mapUtil.getMap().invalidateSize();
        mapUtil.getMap()._onResize(); // force refresh for vector tiles
        if (window.layerMVT) {
          window.layerMVT.redraw();
        }
      }
    },

    initMap() {
      this.zoom = this.$route.query.zoom || '';
      this.lat = this.$route.query.lat || '';
      this.lng = this.$route.query.lng || '';

      var mapDefaultViewCenter =
        this.$store.state.configuration.DEFAULT_MAP_VIEW.center;
      var mapDefaultViewZoom =
        this.$store.state.configuration.DEFAULT_MAP_VIEW.zoom;

      this.map = mapUtil.createMap(this.$refs.map, {
        zoom: this.zoom,
        lat: this.lat,
        lng: this.lng,
        mapDefaultViewCenter,
        mapDefaultViewZoom,
      });

      this.fetchBboxNfit();

      document.addEventListener('change-layers-order', (event) => {
        // Reverse is done because the first layer in order has to be added in the map in last.
        // Slice is done because reverse() changes the original array, so we make a copy first
        mapUtil.updateOrder(event.detail.layers.slice().reverse());
      });

      // --------- End sidebar events ----------

      setTimeout(() => {
        const project_id = this.projectSlug.split('-')[0];
        const mvtUrl = `${this.API_BASE_URL}features.mvt/?tile={z}/{x}/{y}&project_id=${project_id}`;
        mapUtil.addVectorTileLayer(
          mvtUrl,
          this.projectSlug,
          this.feature_types,
          this.form
        );
        mapUtil.addGeocoders(this.$store.state.configuration);
      }, 1000);
    },

    fetchBboxNfit(queryParams) {
      featureAPI
        .getFeaturesBbox(this.projectSlug, queryParams)
        .then((bbox) => {
          if (bbox) {
            mapUtil.getMap().fitBounds(bbox, { padding: [25, 25] });
          }
        });
    },

    //* Paginated Features for table *//
    getFeatureTypeSlug(title) {
      const featureType = this.feature_types.find((el) => el.title === title);
      return featureType ? featureType.slug : null;
    },

    getAvalaibleField(orderField) {
      let result = orderField;
      if (orderField === 'display_creator') {
        result = 'creator';
      } else if (orderField === 'display_last_editor') {
        result = 'last_editor';
      }
      return result;
    },

    buildQueryString() {
      let urlParams = '';
      let typeFilter = this.getFeatureTypeSlug(this.form.type.selected);
      let statusFilter = this.form.status.selected.value;

      if (typeFilter) urlParams += `&feature_type_slug=${typeFilter}`;
      if (statusFilter) urlParams += `&status__value=${statusFilter}`;
      if (this.form.title) urlParams += `&title=${this.form.title}`;
      if (this.sort.column) {
        urlParams += `&ordering=${
          this.sort.ascending ? '-' : ''
        }${this.getAvalaibleField(this.sort.column)}`;
      }
      return urlParams;
    },

    fetchPagedFeatures(newUrl) {
      let url = `${this.API_BASE_URL}projects/${this.projectSlug}/feature-paginated/?output=geojson&limit=${this.pagination.pagesize}&offset=${this.pagination.start}`;
      //* if receiving next & previous url
      if (newUrl && typeof newUrl === 'string') {
        //newUrl = newUrl.replace("8000", "8010"); //* for dev uncomment to use proxy link
        url = newUrl;
      }
      const queryString = this.buildQueryString();
      url += queryString;

      this.$store.commit(
        'DISPLAY_LOADER',
        'Récupération des signalements en cours...'
      );
      featureAPI.getPaginatedFeatures(url)
        .then((data) => {
          if (data) {
            this.featuresCount = data.count;
            this.previous = data.previous;
            this.next = data.next;
            this.paginatedFeatures = data.results.features;
          }
          //* bbox needs to be updated with the same filters
          if (this.paginatedFeatures.length) {
            this.fetchBboxNfit(queryString);
            this.onFilterChange(); //* use paginated event to watch change in filters and modify features on map
          }
          this.$store.commit('DISCARD_LOADER');
        });
    },

    resetPaginationNfetchFeatures() {
      this.pagination = {
        currentPage: 1,
        pagesize: 15,
        start: 0,
        end: 15,
      },
      this.fetchPagedFeatures();
    },

    //* Pagination for table *//

    handlePageChange(page) {
      if (page === 'next') {
        this.toNextPage();
      } else if (page === 'previous') {
        this.toPreviousPage();
      } else if (typeof page === 'number') {
        //* update limit and offset
        this.toPage(page);
      }
    },

    handleSortChange(sort) {
      this.sort = sort;
      this.fetchPagedFeatures({
        filterType: undefined,
        filterValue: undefined,
      });
    },

    toPage(pageNumber) {
      const toAddOrRemove =
        (pageNumber - this.pagination.currentPage) * this.pagination.pagesize;
      this.pagination.start += toAddOrRemove;
      this.pagination.end += toAddOrRemove;
      this.pagination.currentPage = pageNumber;
      this.fetchPagedFeatures();
    },

    toPreviousPage() {
      if (this.pagination.currentPage !== 1) {
        if (this.pagination.start > 0) {
          this.pagination.start -= this.pagination.pagesize;
          this.pagination.end -= this.pagination.pagesize;
          this.pagination.currentPage -= 1;
        }
        this.fetchPagedFeatures(this.previous);
      }
    },

    toNextPage() {
      if (this.pagination.currentPage !== this.pageNumbers.length) {
        if (this.pagination.end < this.featuresCount) {
          this.pagination.start += this.pagination.pagesize;
          this.pagination.end += this.pagination.pagesize;
          this.pagination.currentPage += 1;
        }
        this.fetchPagedFeatures(this.next);
      }
    },
  },
};
</script>


<style scoped>
#map {
  width: 100%;
  min-height: 300px;
  height: calc(100vh - 300px);
  border: 1px solid grey;
  /* To not hide the filters */
  z-index: 1;
}

#feature-list-container {
  justify-content: flex-start;
}

#feature-list-container .ui.menu:not(.vertical) .right.item {
  padding-right: 0;
}

.map-container {
  width: 80vw;
  transform: translateX(-50%);
  margin-left: 50%;
  visibility: hidden;
  position: absolute;
}
.map-container.visible {
  visibility: visible;
  position: initial;
}

.margin-left-25 {
  margin-left: 0.25em !important;
}

.no-padding {
  padding: 0 !important;
}

.ui.dropdown .menu .left.menu, .ui.dropdown > .left.menu .menu {
  margin-right: 0 !important;
}

#button-dropdown {
  z-index: 1;
}

@media screen and (min-width: 767px) {
  .twelve-wide {
    width: 75% !important;
  }
}

@media screen and (max-width: 767px) {
  #feature-list-container > .mobile-fullwidth {
    width: 100% !important;
  }
  .no-margin-mobile {
    margin: 0 !important;
  }
  .no-padding-mobile {
    padding-top: 0 !important;
    padding-bottom: 0 !important;
  }
  .mobile-column {
    flex-direction: column !important;
  }
  #button-dropdown {
    transform: translate(-50px, -60px);
  }
  #form-filters > .field.column {
    width: 100% !important;
  }
  .map-container {
    width: 100%;
  }
}
</style>