<!-- Search for member structures -->

<template>
  <LayoutContainer>
    <!-- Header -->
    <v-row>
      <v-layout>
        <h2 class="flex">
          {{ $t("member_companies") }}
        </h2>
        <v-btn-toggle mandatory dense :value="mapview ? 0 : 1" @change="viewChanged">
          <v-btn>
            {{ $t("map") }}
          </v-btn>
          <v-btn>
            {{ $t("list") }}
          </v-btn>
        </v-btn-toggle>
      </v-layout>
    </v-row>

    <v-row>
      <!-- Map Column (hidden in 'list-view' mode)-->
      <v-col
        v-if="mapview"
        cols="12"
        sm="6"
      >
        <no-ssr>
          <UiMapStructures
            ref="map"
            :structures="filteredStructures"
            :zoom-at-start="mapZoomAtStart"
            @boundsUpdated="mapBoundsFilterChanged"
          />
        </no-ssr>
      </v-col>

      <!-- Results column -->
      <v-col
        cols="12"
        :sm="mapview ? 6 : 12"
      >
        <!-- Search form -->
        <v-row>
          <v-form method="get" class="mt-8 w100">
            <v-container>
              <v-row>
                <v-col cols="12" md="6" class="py-2 px-1">
                  <v-text-field
                    v-model="textFilter"
                    type="text"
                    outlined
                    clearable
                    hide-details
                    append-icon="mdi-magnify"
                    :label="$t('what') + ' ?'"
                    @click:append="search"
                    @keydown.enter="search"
                  />
                </v-col>

                <v-col cols="12" md="6" class="py-2 px-1">
                  <UiSearchAddress
                    ref="addressSearch"
                    type="municipality"
                    @change="locationFilterChanged"
                  />
                </v-col>
              </v-row>

              <v-row>
                <v-col v-if="listview && $vuetify.breakpoint.mdAndUp" cols="2" class="py-2 px-1">
                  <v-btn class="h100" @click="reinitializeFilters">
                    {{ $t('reinitialize') }}
                  </v-btn>
                </v-col>
                <v-col :cols="(listview && $vuetify.breakpoint.mdAndUp) ? 8 : 12">
                  <v-row class="filters">
                    <v-col lg="3" :md="listview ? 3 : 6" sm="6" cols="12" class="py-2 px-1">
                      <v-autocomplete
                        v-model="practicesFilter"
                        :label="$t('type')"
                        :items="translatedPractices"
                        item-value="id"
                        item-text="label"
                        filled
                        hide-details
                        hide-no-data
                        :filter="enhancedAutocompleteFilter"
                        @change="search"
                      />
                    </v-col>
                    <v-col lg="3" :md="listview ? 3 : 6" sm="6" cols="12" class="py-2 px-1">
                      <v-autocomplete
                        v-model="departmentFilter"
                        :items="departments"
                        item-value="code"
                        item-text="label"
                        :label="$t('department')"
                        filled
                        hide-details
                        hide-no-data
                        :filter="enhancedAutocompleteFilter"
                        @change="search"
                      />
                    </v-col>
                    <v-col lg="3" :md="listview ? 3 : 6" sm="6" cols="12" class="py-2 px-1">
                      <v-autocomplete
                        v-model="federationFilter"
                        :items="federations"
                        item-value="id"
                        item-text="name"
                        :label="$t('federation')"
                        filled
                        hide-details
                        hide-no-data
                        :filter="enhancedAutocompleteFilter"
                        @change="search"
                      />
                    </v-col>
                    <v-col lg="3" :md="listview ? 3 : 6" sm="6" cols="12" class="py-2 px-1">
                      <v-select
                        v-model="distanceFilter"
                        :label="$t('distance')"
                        :items="[
                          {distance: 10, label: '10km'},
                          {distance: 30, label: '30km'},
                          {distance: 100, label: '100km'},
                          {distance: 200, label: '200km'}
                        ]"
                        item-value="distance"
                        item-text="label"
                        filled
                        hide-details
                        @change="search"
                      />
                    </v-col>
                  </v-row>
                </v-col>
                <v-col v-if="listview && $vuetify.breakpoint.mdAndUp" cols="2" class="py-2 px-1 d-flex justify-end">
                  <v-btn class="h100">
                    {{ $t('search') }}
                  </v-btn>
                </v-col>
              </v-row>

              <v-row v-show="mapview || $vuetify.breakpoint.smAndDown" class="px-2 pt-2">
                <v-btn @click="reinitializeFilters">
                  {{ $t('reinitialize') }}
                </v-btn>
                <v-spacer />
                <v-btn @click="search">
                  {{ $t('search') }}
                </v-btn>
              </v-row>
            </v-container>
          </v-form>
        </v-row>

        <div class="pt-4 mt-6">
          <!-- loading skeleton -->
          <v-container v-if="$fetchState.pending">
            <v-row v-for="i in 3" :key="i" justify="space-between" class="mt-1 mb-3">
              <v-col v-for="j in 2" :key="j" cols="12" :md="mapview ? 6 : 12" class="py-2 px-1">
                <v-skeleton-loader type="card" :loading="true" />
              </v-col>
            </v-row>
          </v-container>

          <!-- Results -->
          <v-data-iterator
            v-else
            :items="onMapFilteredStructures"
            :page.sync="page"
            :items-per-page="itemsPerPage"
            sort-by="name"
            hide-default-footer
            no-data-text=""
          >
            <template #header>
              <i class="results-count">{{ totalRecords }} {{ $t('results') }}</i>
            </template>
            <template #default="props">
              <v-row justify="space-between" class="mt-1 mb-3">
                <v-col
                  v-for="structure in props.items"
                  :key="structure.name"
                  cols="12"
                  sm="12"
                  :lg="mapview ? 6 : 12"
                  class="py-2 px-1"
                >
                  <v-card
                    elevation="1"
                    outlined
                    :class="'structure-card pa-3 d-flex ' + ((mapview || $vuetify.breakpoint.smAndDown) ? 'flex-column' : 'flex-row align-items-center')"
                  >
                    <div class="d-flex justify-center max-w100" >
                      <v-img
                        v-if="structure.logoId"
                        :src="'https://api.opentalent.fr/app.php/_internal/secure/files/' + structure.logoId"
                        alt="poster"
                        height="80"
                        width="240"
                        max-height="100%"
                        :contain="true"
                        style="margin: 12px;"
                      />
                      <v-skeleton-loader
                        v-else
                        type="card-avatar"
                        boilerplate
                        width="164px"
                        height="84px"
                        style="margin: 10px 50px;"
                      />
                    </div>

                    <div :class="'d-flex flex-column' + (listview ? ' flex-grow-1' : '')">

                      <v-card-title class="title">
                        <nuxt-link :to="{path: '/structures/' + structure.id, query: { parent: parent, view: view, theme: theme }}">
                          {{ structure.name }}
                        </nuxt-link>
                      </v-card-title>

                      <v-card-text class="infos">
                        <table>
                          <tr>
                            <td>
                              <font-awesome-icon class="icon" :icon="['fas', 'map-marker-alt']" />
                            </td>
                            <td>
                              <span v-if="structure.streetAddress">{{ structure.streetAddress }}<br></span>
                              <span v-if="structure.postalCode" class="postalCode">{{ structure.postalCode }} </span>
                              {{ structure.addressCity }}
                            </td>
                          </tr>
                          <tr>
                            <td>
                              <font-awesome-icon class="icon" :icon="['fas', 'project-diagram']" />
                            </td>
                            <td>
                              <NuxtLink
                                v-if="structure.n1Id !== parent"
                                class="neutral"
                                :to="{path: '/structures/' + structure.n1Id, query: { parent: parent, view: view, theme: theme }}"
                                nuxt
                              >
                                {{ structure.n1Name }}
                              </NuxtLink>
                              <div v-else>
                                {{ structure.n1Name }}
                              </div>
                            </td>
                          </tr>
                        </table>
                      </v-card-text>
                    </div>

                    <div
                      v-if="structure.practices"
                      class="d-grid flex-wrap"
                      :style="listview ? 'width: 25%;min-width: 25%;' : ''"
                    >
                      <v-chip
                        v-for="practice in structure.practices"
                        :key="practice"
                        class="ma-1"
                        label
                        small
                      >
                        {{ $t(practice) }}
                      </v-chip>
                    </div>

                    <span v-if="mapview" class="flex-fill" />

                    <v-card-actions :class="listview ? 'align-self-end' : ''">
                      <v-btn
                        class="see"
                        :to="{path: '/structures/' + structure.id, query: { parent: parent, view: view, theme: theme }}"
                        nuxt
                      >
                        <span style="margin-right: 6px;">{{ $t("see_more") }}</span>
                        <font-awesome-icon :icon="['fa', 'caret-right']" />
                      </v-btn>
                    </v-card-actions>
                  </v-card>
                </v-col>
              </v-row>
            </template>

            <template #footer>
              <v-pagination
                v-model="page"
                :length="pageCount"
                total-visible="9"
                color="primary"
              />
            </template>
          </v-data-iterator>
        </div>
      </v-col>
    </v-row>
  </LayoutContainer>
</template>

<script lang="ts">
import Vue from 'vue'
import { LatLngBounds } from 'leaflet'
import departments from '@/enums/departments'
import practices from '@/enums/practices'
import sphericDistance from '@/services/utils/geo'
import StructuresProvider from '~/services/data/StructuresProvider'

const CMF_ID = 12097

export default Vue.extend({
  validate ({ query }) {
    if (!/^\d+$/.test(query.parent as string ?? '')) {
      // eslint-disable-next-line no-console
      console.error('Missing parameter: parent')
      return false
    }
    if (query.view && !['map', 'list'].includes(query.view as string)) {
      // eslint-disable-next-line no-console
      console.error('Invalid parameter: view')
      return false
    }
    return true
  },
  data () {
    return {
      parent: parseInt(this.$route.query.parent as string),
      view: this.$route.query.view ?? 'map',
      theme: this.$route.query.theme ?? 'orange',
      structures: [] as Array<Structure>,
      filteredStructures: [] as Array<Structure>,
      federations: [] as Array<{ id: number | null, name: string | null }>,
      loading: true,
      page: 1,
      itemsPerPage: 8,
      departments: departments as {code: string, label: string}[],
      practices: practices as {id: string}[],
      textFilter: null as string | null,
      locationFilter: null as Coordinates | null,
      practicesFilter: null as string | null,
      departmentFilter: null as string | null,
      federationFilter: null as number | null,
      distanceFilter: null as number | null,
      mapBoundsFilter: null as LatLngBounds | null,
      mapBoundsFilterStarted: false, // map bounds filter is only activated when the map bounds are updated
      mapZoomAtStart: false
    }
  },
  async fetch () {
    await new StructuresProvider(this.$axios).getAll(this.parent).then(
      (res) => {
        this.structures = res
        this.filteredStructures = res

        // populate federations filter
        for (const s of res) {
          const f = {
            id: s.n1Id,
            name: s.n1Name
          }
          if (!this.federations.includes(f)) {
            this.federations.push(f)
          }
        }

        // zoom on map markers (except if the parent structure is the CMF)
        if (this.parent !== CMF_ID) {
          this.mapZoomAtStart = true
        }
      })
  },
  computed: {
    onMapFilteredStructures (): Array<Structure> {
      if (this.mapview && this.mapBoundsFilterStarted) {
        return this.filteredStructures.filter((s) => {
          return this.matchMapBounds(s)
        })
      } else {
        return this.filteredStructures
      }
    },
    totalRecords (): number {
      return this.onMapFilteredStructures.length
    },
    pageCount (): number {
      return Math.floor(this.totalRecords / this.itemsPerPage) + 1
    },
    mapview (): boolean {
      return this.view === 'map'
    },
    listview (): boolean {
      return this.view === 'list'
    },
    translatedPractices (): Array<{ id: string, label: string }> {
      const tPractices = []
      for (const practice of this.practices) {
        tPractices.push({ id: practice.id, label: this.$t(practice.id) as string })
      }
      return tPractices
    }
  },
  methods: {
    viewChanged (e: number) {
      this.view = (e === 0) ? 'map' : 'list'
      if (this.mapview) {
        this.mapZoomAtStart = true
      }
    },
    textFilterChanged (newVal: string) {
      this.textFilter = newVal
    },
    locationFilterChanged (newVal: Coordinates) {
      this.locationFilter = newVal
      if (this.distanceFilter === null) {
        this.distanceFilter = 10
      }
      this.search()
    },
    resetMap (): void {
      const map = this.$refs.map as any
      map.resetBounds()
      if (this.parent !== CMF_ID) {
        this.fitMapToResults()
      }
      this.mapBoundsFilterStarted = false
    },
    fitMapToResults (): void {
      (this.$refs.map as any).zoomOnResults()
    },
    mapBoundsFilterChanged (newBounds: LatLngBounds) {
      this.mapBoundsFilterStarted = true
      this.mapBoundsFilter = newBounds
    },
    reinitializeFilters (): void {
      this.textFilter = null
      this.locationFilter = null
      this.practicesFilter = null
      this.departmentFilter = null
      this.federationFilter = null
      this.distanceFilter = null
      this.mapBoundsFilter = null
      const addressSearch = this.$refs.addressSearch as any
      addressSearch.clear()
      this.resetMap()
      this.filteredStructures = this.structures
    },
    /**
     * Does the structure match the current textFilter
     * @param structure
     * @returns {boolean}
     */
    matchTextFilter (structure: Structure): boolean {
      if (!this.textFilter) { return true }

      return this.searchTextNormalize(structure.name).includes(this.searchTextNormalize(this.textFilter))
    },
    /**
     * Does the structure match the current locationFilter
     * @param structure
     * @returns {boolean}
     */
    matchLocationFilter (structure: Structure): boolean {
      if (!this.locationFilter) { return true }
      if (!structure.latitude || !structure.longitude) { return false }

      const radius = Number(this.distanceFilter) ?? 5

      return sphericDistance(
        this.locationFilter.latitude, this.locationFilter.longitude, structure.latitude, structure.longitude
      ) <= radius
    },
    /**
     * Does the structure match the current practicesFilter
     * @param structure
     * @returns {boolean}
     */
    matchPracticesFilter (structure: Structure): boolean {
      if (!this.practicesFilter) { return true }
      return structure.practices && structure.practices.includes(this.practicesFilter)
    },
    /**
     * Does the structure match the current departmentFilter
     * @param structure
     * @returns {boolean}
     */
    matchDepartmentFilter (structure: Structure): boolean {
      if (!this.departmentFilter) { return true }
      return structure.postalCode !== null &&
        (
          structure.postalCode.startsWith(this.departmentFilter) ||
          (['2A', '2B'].includes(this.departmentFilter) && structure.postalCode.startsWith('20'))
        )
    },
    /**
     * Does the structure match the current federationFilter
     * @param structure
     * @returns {boolean}
     */
    matchFederationFilter (structure: Structure): boolean {
      if (!this.federationFilter) { return true }
      return structure.parents.includes(this.federationFilter)
    },
    /**
     * Does the structure match the current federationFilter
     * @param structure
     * @returns {boolean}
     */
    matchMapBounds (structure: Structure): boolean {
      if (!this.mapBoundsFilter) { return true }
      if (!(structure.latitude && structure.longitude)) { return false }
      return this.mapBoundsFilter.getSouth() <= structure.latitude &&
             structure.latitude <= this.mapBoundsFilter.getNorth() &&
             this.mapBoundsFilter.getWest() <= structure.longitude &&
             structure.longitude <= this.mapBoundsFilter.getEast()
    },
    /**
     * Does the structure match each of the page filters
     * @param structure
     * @returns {boolean}
     */
    matchFilters (structure: Structure): boolean {
      return this.matchTextFilter(structure) &&
        this.matchLocationFilter(structure) &&
        this.matchPracticesFilter(structure) &&
        this.matchDepartmentFilter(structure) &&
        this.matchFederationFilter(structure)
    },
    /**
     * Update the filteredStructures array
     */
    search (): void {
      this.filteredStructures = this.structures.filter((s) => { return this.matchFilters(s) })
      if (this.mapview) {
        this.fitMapToResults()
      }
    },
    searchTextNormalize (s: string): string {
      return s
        .toLowerCase()
        .replace(/[éèẽëê]/g, 'e')
        .replace(/[ç]/g, 'c')
        .replace(/[îïĩ]/g, 'i')
        .replace(/[àã]/g, 'a')
        .replace(/[öôõ]/g, 'o')
        .replace(/[ûüũ]/g, 'u')
        .replace(/[-]/g, ' ')
        .trim()
    },
    /**
     * Enhanced filter for v-autocomplete components
     *
     * @param _
     * @param queryText
     * @param itemText
     */
    enhancedAutocompleteFilter (_: any, queryText: string, itemText: string): boolean {
      return this.searchTextNormalize(itemText).includes(this.searchTextNormalize(queryText))
    }
  }
})
</script>

<style scoped lang="scss">
  @import 'assets/style/variables.scss';

  h2 {
    color: var(--v-primary-base);
  }

  .structure-card {
    height: 100%;
    color: #666666;
  }

  .infos .col {
    padding: 6px 12px;
  }

  .infos td {
    padding: 4px;
    vertical-align: top;
  }
  .infos td:first-child {
    padding-top: 6px;
    text-align: center;
  }

  .title {
    word-break: normal;
    color: var(--v-primary-base);
    font-size: 18px;
    font-weight: 500;
    line-height: 1.6rem;
  }

  .title a {
    text-decoration: none;
  }

  .icon {
    color: var(--v-primary-base);
  }

  .results-count {
    font-size: .8em;
    color: #666;
  }
</style>
