<template>
  <v-app class="agenda-application border-box-sizing" flat>
    <template v-if="settingsLoaded && !hideApp">
      <v-main class="application-body" :class="$root.isMobile ? 'pt-2 px-1' : ''">
        <agenda-header
          :calendar-type="calendarType"
          :event-type="eventType"
          :current-space="currentSpace"
          :current-calendar="currentCalendar"
          :owner-ids="ownerIds"
          :period-title="periodTitle"
          :settings="settings"
          :period="period"
          :connectors="enabledConnectors" />
        <agenda-timeline
          v-if="$root.isMobile"
          :events="displayedEvent"
          :period-start-date="period.start"
          :loading="loading"
          :limit="limit"
          :connected-connector-avatar="connectedConnectorAvatar"
          class="mt-2 pa-5" />
        <agenda-body
          v-else
          :events="displayedEvent"
          :current-calendar="currentCalendar"
          :calendar-type="calendarType"
          :weekdays="weekdays"
          :full-weekdays="fullWeekdays"
          :working-time="workingTime"
          :connected-connector-avatar="connectedConnectorAvatar" />  
        <v-flex v-if="$root.isMobile && hasMore" class="d-flex py-4 border-box-sizing">
          <v-btn
            :loading="loading"
            :disabled="loading"
            class="btn mx-auto"
            @click="limit += pageSize">
            {{ $t('agenda.button.loadMore') }}
          </v-btn>
        </v-flex>
      </v-main>
    </template>

    <agenda-event-dialog
      ref="eventFormDialog"
      :current-space="currentSpace"
      :current-calendar="currentCalendar"
      :settings="settings"
      :connectors="enabledConnectors"
      :conference-provider="conferenceProvider"
      :weekdays="fullWeekdays"
      :working-time="workingTime" />
    <agenda-event-preview-dialog />
    <agenda-filter-calendar-drawer
      :current-space="currentSpace"
      :settings="settings"
      :calendar-type="calendarType" />
    <agenda-user-setting-drawer :settings="settings" />
    <agenda-event-quick-form-drawer
      :current-space="currentSpace"
      :current-calendar="currentCalendar"
      :settings="settings"
      :conference-provider="conferenceProvider" />
    <agenda-event-save />
    <agenda-connector
      :settings="settings"
      :connectors="connectors"
      @connectors-loaded="connectors = $event" />
    <agenda-notification-alerts />
    <agenda-events-updater
      v-if="settingsLoaded"
      :settings="settings"
      :current-calendar="currentCalendar"
      :calendar-type="eventType"
      :owner-ids="ownerIds"
      :events="events"
      :period="period"
      :limit="limit" />
    <agenda-pending-invitation-drawer :current-space="currentSpace" />
    <agenda-connectors-drawer :connectors="connectors" />
  </v-app>
</template>
<script>
export default {
  props: {
    eventType: {
      type: String,
      // allEvents, declinedEvent or myEvents
      default: () => 'myEvents',
    },
    hideApp: {
      type: Boolean,
      default: false,
    },
  },
  data: () => ({
    initialized: false,
    currentCalendar: null,
    currentSpace: null,
    filterCanceledEvents: true,
    loading: false,
    conferenceProviders: null,
    connectors: [],
    ownerIds: [],
    searchTerm: null,
    periodTitle: '',
    calendarType: 'week',
    pageSize: 10,
    limit: 0,
    period: {
      start: new Date(),
      end: null,
    },
    events: [],
    remoteEvents: [],
    settings: {
      agendaDefaultView: 'week',
      agendaWeekStartOn: 'MO',
      showWorkingTime: false,
      workingTimeStart: '08:00',
      workingTimeEnd: '18:00',
    },
    hasMore: false,
    settingsLoaded: false,
    remoteEventsLoaded: false,
  }),
  computed: {
    enabledConferenceProviderName() {
      return this.settings
          && this.conferenceProviders
          && this.conferenceProviders.length > 0
          && this.conferenceProviders.find((provider) => provider.configured);
    },
    conferenceProvider() {
      return this.conferenceProviders && this.enabledConferenceProviderName && this.conferenceProviders.find(provider => provider.isInitialized && provider.linkSupported && provider.groupSupported && this.enabledConferenceProviderName.getType() === provider.getType());
    },
    enabledConnectors() {
      return this.connectors && this.connectors.filter(connector => connector.initialized && connector.enabled) || [];
    },
    connectedConnector() {
      return this.connectors && this.connectors.find(connector => connector.connected);
    },
    signedInConnector() {
      return this.connectedConnector && this.connectedConnector.isSignedIn;
    },
    connectorStatus() {
      if (this.connectedConnector) {
        if (this.connectedConnector.isSignedIn) {
          return 1;
        } else {
          return 2;
        }
      } else {
        return 0;
      }
    },
    weekdays() {
      return this.settings && this.$agendaUtils.getWeekSequenceFromDay(this.settings, this.calendarType, false);
    },
    fullWeekdays() {
      return this.settings && this.$agendaUtils.getWeekSequenceFromDay(this.settings, this.calendarType, true);
    },
    workingTime() {
      return this.settings && {
        showWorkingTime: this.settings.showWorkingTime,
        workingTimeStart: this.settings.workingTimeStart,
        workingTimeEnd: this.settings.workingTimeEnd,
        workedDaysNumber: this.settings.workedDaysNumber,
      };
    },
    displayedEvent() {
      if (this.settings.showRemoteEventsForAgenda){
        // Avoid to have same event from remote and local store (pushed events from local store)
        const filtredRemoteEvents = this.filterRemoteEvents(this.events, this.remoteEvents);
        const events = this.events.concat(filtredRemoteEvents);
        return  events.sort((event1, event2) => {
          const eventStart1 = this.$agendaUtils.toDate(event1.start || event1.startDate).getTime();
          const eventStart2 = this.$agendaUtils.toDate(event2.start || event2.startDate).getTime();
          return eventStart1 - eventStart2;
        });
      }
      return  this.events;
    },
    connectedConnectorAvatar() {
      return this.connectedConnector && this.connectedConnector.avatar || '';
    },
  },
  watch: {
    limit() {
      this.retrieveEvents();
    },
    eventType() {
      this.retrieveEvents();
    },
    initialized() {
      if (this.initialized) {
        this.$root.$emit('agenda-application-loaded');
      }
    },
    period() {
      this.retrieveEvents();
      if (this.settings.showRemoteEventsForAgenda && this.signedInConnector) {
        this.retrieveRemoteEvents();
      }
    },
    searchTerm() {
      this.retrieveEvents();
    },
    loading() {
      if (this.loading) {
        document.dispatchEvent(new CustomEvent('displayTopBarLoading'));
      } else {
        this.$root.$applicationLoaded();
        document.dispatchEvent(new CustomEvent('hideTopBarLoading'));
      }
    },
    signedInConnector() {
      if (this.signedInConnector && this.settings.showRemoteEventsForAgenda) {
        this.retrieveRemoteEvents();
      }
    }
  },
  created() {
    // Ensure that localStorage doesn't have a deleted event
    window.setTimeout(() => {
      localStorage.removeItem('agendaDeletedEvents');
    }, 10000);

    this.$root.$on('agenda-change-period', period => {
      this.period = period;
      this.periodTitle = this.generateCalendarTitle(period);
    });
    this.$root.$on('agenda-event-limit-increment', () => this.limit += this.pageSize);
    this.$root.$on('agenda-change-period-type', calendarType => this.calendarType = calendarType);
    this.$root.$on('agenda-search', searchTerm => this.searchTerm = searchTerm);
    this.$root.$on('agenda-event-saved', this.savedEvent);
    this.$root.$on('agenda-refresh', this.retrieveEvents);
    this.$root.$on('agenda-event-type-changed', eventType => this.eventType = eventType);
    this.$root.$on('agenda-event-deleted', this.deletedEvent);
    this.$root.$on('agenda-event-response-sent', this.retrieveEvents);
    this.spaceId = eXo.env.portal.spaceId;
    this.$root.$on('agenda-settings-refresh', this.initSettings);
    this.$root.$on('agenda-event-change-owner', this.refreshProviders);
    this.$root.$on('agenda-show-remote-change', this.showRemoteEvents);
    this.initSettings();
  },
  methods: {
    initSettings(userSettings) {
      if (userSettings) {
        this.settings = userSettings;
      } else {
        return this.$settingsService.getUserSettings()
          .then(settings => {
            if (settings) {
              this.settings = settings;
              this.calendarType = this.settings && this.settings.agendaDefaultView;
              this.refreshProviders(eXo.env.portal.spaceName);
            }
          })
          .finally(() => {
            this.settingsLoaded = true;
          });
      }
    },
    refreshProviders(spacePrettyName) {
      if (spacePrettyName) {
        this.$webConferencingService.getAllProviders(spacePrettyName).then(providers => {
          this.conferenceProviders = providers;
          return this.$nextTick();
        });
      } else {
        this.conferenceProviders = null;
      }
    },
    showRemoteEvents(showRemoteEvents) {
      if (this.settings.showRemoteEventsForAgenda !== showRemoteEvents){
        this.settings.showRemoteEventsForAgenda = showRemoteEvents;
        this.$settingsService.saveUserSettings(this.settings);
        if (showRemoteEvents && !this.remoteEventsLoaded) {
          this.retrieveRemoteEvents();
        }
      }
    },
    retrieveEvents() {
      if (!this.initialized && eXo.env.portal.spaceId) {
        const spaceId = eXo.env.portal.spaceId;
        this.$spaceService.getSpaceById(spaceId, 'identity')
          .then((space) => {
            this.currentSpace = space;
            this.eventType = space ? 'allEvents' : 'myEvents';
            if (space && space.identity && space.identity.id) {
              this.ownerIds = [space.identity.id];
            }
            if (this.ownerIds && this.ownerIds.length) {
              return this.$calendarService.getCalendars(0, 1, false, this.ownerIds);
            }
          })
          .then(data => {
            this.currentCalendar = data && data.calendars && data.calendars.length && data.calendars[0] || null;
          })
          .finally(() => {
            this.retrieveEventsFromStore();
          });
      } else {
        this.retrieveEventsFromStore();
      }
    },
    retrieveEventsFromStore() {
      this.loading = true;
      const userIdentityId = this.eventType !== 'allEvents' && eXo.env.portal.userIdentityId || null;
      if (this.ownerIds === false) {
        this.events = [];
        this.hasMore = false;
        this.loading = false;
        this.initialized = true;
        return;
      }
      const responseTypes = userIdentityId ?
        this.eventType === 'declinedEvent' ? ['DECLINED']:['ACCEPTED', 'NEEDS_ACTION', 'TENTATIVE']
        : null;
      return this.$eventService.getEvents(this.searchTerm, this.ownerIds, userIdentityId, this.$agendaUtils.toRFC3339(this.period.start, true), this.$agendaUtils.toRFC3339(this.period.end), this.limit, responseTypes, 'attendees,conferences')
        .then(data => {
          let events = data && data.events || [];
          if (this.filterCanceledEvents) {
            events = events.filter(event => !event.status || event.status !== 'CANCELLED');
          }
          events.forEach(event => {
            event.name = event.summary;
            event.startDate = event.start && this.$agendaUtils.toDate(event.start) || null;
            event.endDate = event.end && this.$agendaUtils.toDate(event.end) || null;
          });
          this.hasMore = this.limit > this.pageSize && (this.events && this.events.length || 0) < events.length || events.length >= this.limit;
          this.events = events;
        }).catch(error =>{
          console.error('Error retrieving events', error);
        }).finally(() => {
          this.initialized = true;
          this.loading = false;
        });
    },
    generateCalendarTitle(period) {
      return this.$agendaUtils.generateCalendarTitle(this.calendarType, this.$agendaUtils.toDate(period.start), period.title, this.$t('agenda.week'));
    },
    changeDisplayedOwnerIds(selectedOwnerIds) {
      this.ownerIds = selectedOwnerIds;
      this.retrieveEvents();
    },
    updateSettings(settings) {
      this.settings = settings;
    },
    savedEvent(event) {
      if (event && event.id) {
        const isDatePoll = event.status === 'TENTATIVE';
        const isNew = !event.updated;
        const message = isDatePoll && (isNew && this.$t('agenda.datePollCreationSuccess') || this.$t('agenda.datePollUpdateSuccess'))
                     || (isNew && this.$t('agenda.eventCreationSuccess') || this.$t('agenda.eventUpdateSuccess'));
        const clickMessage = isDatePoll && this.$t('agenda.viewDatePoll') || this.$t('agenda.viewEvent');
        document.dispatchEvent(new CustomEvent('alert-message', {detail: {
          alertType: 'success',
          alertMessage: message,
          alertLinkText: clickMessage,
          alertLinkCallback: () => this.$root.$emit('agenda-event-details', event),
        }}));
      }
    },
    deletedEvent(event, untilDateRecurrenceUpdated) {
      if (event && event.id) {
        const isDatePoll = event.status === 'TENTATIVE';
        const message = isDatePoll
                        && this.$t('agenda.datePollDeleteSuccess')
                        || (untilDateRecurrenceUpdated && this.$t('agenda.eventRecurrenceUntilDateUpdated'))
                        || this.$t('agenda.eventDeleteSuccess');     
        const deleteEventAlert = {detail: {
          alertType: 'success',
          alertMessage: message,
        }};
        if (isDatePoll || !untilDateRecurrenceUpdated) {
          deleteEventAlert.detail.alertLinkText = this.$t('agenda.undoRemoveEvent');
          deleteEventAlert.detail.alertLinkCallback = () => this.undoDeleteEvent(event);
        }
        document.dispatchEvent(new CustomEvent('alert-message', deleteEventAlert));
      }
    },
    undoDeleteEvent(event) {
      if (event.occurrence && event.occurrence.id) {
        return this.$eventService.updateEventFields(event.id, {status: 'CONFIRMED'}, false, true)
          .then(() => {
            this.$root.$emit('agenda-refresh', event);
            this.$root.$emit('alert-message', this.$t('agenda.eventDeletionCanceled'), 'success');
          });
      } else {
        return this.$eventService.undoDeleteEvent(event.id)
          .then(() => {
            this.$root.$emit('agenda-refresh', event);
            this.$root.$emit('alert-message', this.$t('agenda.eventDeletionCanceled'), 'success');
          });
      }
    },
    retrieveRemoteEvents() {
      if (this.connectorStatus === 1) {
        const startDateRFC3359 = this.$agendaUtils.toRFC3339(this.period.start, false, true);
        const endDateRFC3359 = this.$agendaUtils.toRFC3339(this.period.end, false, true);
        this.loading = true;
        this.connectedConnector.getEvents(startDateRFC3359, endDateRFC3359)
          .then(events => {
            if (events) {
              events.forEach(event => {
                event.startDate = event.start && this.$agendaUtils.toDate(event.start) || null;
                event.endDate = event.end && this.$agendaUtils.toDate(event.end) || null;
              });
            }
            const remoteEvents = events;
            this.remoteEvents = remoteEvents && remoteEvents.slice() || [];
            this.loading = false;
            this.remoteEventsLoaded = true;
          }).catch(error => {
            this.remoteEvents = [];
            this.loading = false;
            console.error('Error retrieving remote events', error);
          });
      } else {
        this.remoteEvents = [];
      }
    },
    filterRemoteEvents(localEvents, remoteEvents) {
      return remoteEvents.filter(remote => {
        const isMatched = localEvents.some(local => {
          const sameId = remote.id === local.remoteId;
          const sameDates =  new Date(remote.startDate).getTime() === new Date(local.startDate).getTime() && new Date(remote.endDate).getTime() === new Date(local.endDate).getTime();
          const sameRecurring = remote.recurringEventId === local.parent?.remoteId;
          return sameId || (sameRecurring && sameDates);
        });
        return !isMatched;
      });
    }
  },
};
</script>
