<template>
  <div class="q-py-none" v-if="common.active === 'calendar'">
    <q-card class="no-shadow q-pb-md q-gutter-y-md q-mx-md">
      <q-card-section v-if="!hasCalendar">
        <div class="q-my-md">
          <q-banner rounded class="q-mt-md grey-banner q-py-xs">
            <div class="text-grey-9">
              {{ $t('productionCalendar.description') }}
            </div>
          </q-banner>
        </div>
      </q-card-section>
      <q-card-section>
        <BaseProductionCalendar
          v-if="federalWeekendTableVisible"
          :title="$t('productionCalendar.regionInheritCalendar')"
          :readonly="true"
          :week.sync="merged.weekWeekend"
          :work.sync="merged.workWeekend"
          :holid.sync="merged.holidays"
        />
      </q-card-section>
      <q-card-section>
        <BaseProductionCalendar
          v-if="model"
          :title="tableTitle"
          :week.sync="main.weekWeekend"
          :holid.sync="main.holidays"
          :work.sync="main.workWeekend"
          :hasCalendar.sync="hasCalendar"
          :edit="true"
          @saveCalendar="saveCalendar"
        />
      </q-card-section>
    </q-card>
    <q-inner-loading :showing="loading">
      <q-spinner-gears color="primary" size="50px" />
    </q-inner-loading>
  </div>
</template>

<script lang="ts">
import IdmServiceDomains from '@services/idm/domains';
import get from 'lodash/get';
import { CardNeedToUpdateType } from '@constants/models/Card';
import { RestDay, WorkCalendarApi } from '@openapi/idm';
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { BaseCardCommon } from '@/interfaces';
import { notifyError } from '@utils/notify';
import isEqual from 'lodash/isEqual';
import { TranslateResult } from 'vue-i18n';

const workCalendarApi = new WorkCalendarApi();
const RF_ID = 'f13744bf-2af0-4d31-95cf-dfc542bffbec';

@Component({})
export default class ProductionCalendarTab extends Vue {
  @Prop() common: BaseCardCommon;
  @Prop() model: any;

  private loading = false;
  private merged: Calendar = {
    days: [],
    weekWeekend: [],
    holidays: [],
    workWeekend: [],
  };

  private main: Calendar = {
    days: [],
    weekWeekend: [],
    holidays: [],
    workWeekend: [],
  };

  @Watch('model', { immediate: true, deep: true })
  private calendarHandler(model: any, old: any): void {
    if (!isEqual(model, old)) {
      this.init(model);
    }
  }

  get federalWeekendTableVisible() {
    return this.model?.id !== RF_ID;
  }

  get tableTitle(): TranslateResult {
    const russianFederationId = 'f13744bf-2af0-4d31-95cf-dfc542bffbec';

    let title: TranslateResult = '';

    if (this.model.id === russianFederationId) {
      title = this.$t('productionCalendar.regionInheritCalendar');
    } else {
      switch (this.model.schema) {
        case 'Organization':
          title = this.$t('productionCalendar.organizationCalendar');
          break;
        case 'Department':
          title = this.$t('productionCalendar.departmentCalendar');
          break;
        case 'Region':
          title = this.$t('productionCalendar.regionCalendar');
      }
    }

    return title;
  }

  get hasCalendar() {
    return !!(this.model && this.model.calendar);
  }

  get country() {
    return this.$store.getters['idm/regions/country'];
  }

  private async init(model: any): Promise<void> {
    if (model?.calendar?.id) {
      await this.initCalendar(model.calendar.id);
      await this.initMergedCalendar(model.parent?.id || model.id); // model.id for region RF
    } else if (model?.id) {
      await this.initMergedCalendar(model.parent?.id || model.id);
    }
  }

  private saveCalendar(days: RestDay[]): void {
    this.loading = true;

    const newCalendarData = {
      name: `calendar-for-${this.model.id || null}`,
      description: `calendar-for-${this.model.id || null}`,
    };
    const sendData = {
      ...(this.hasCalendar ? this.model.calendar : newCalendarData),
      domainId: this.model.id || null,
      'rest-days': days,
    };
    const calendarSocketListener = (e: any) => {
      const data = JSON.parse(e.data);
      if (data.body.type === 'process' && data.action === 'completed') {
        this.$websockets.removeListener(calendarSocketListener);
        this.$store.commit(
          'utils/cards/needToUpdate',
          CardNeedToUpdateType.MODEL
        );
        this.loading = false;
      }
    };

    this.$websockets.addListener(calendarSocketListener);
    this.$store
      .dispatch('wf/processes/dispatchProcess', {
        processKey: 'IDMCalendarSave',
        data: sendData,
      })
      .catch((e) => notifyError(e.toString()));
  }

  private async initCalendar(id: string) {
    try {
      const { data: calendar } = await workCalendarApi.getWorkCalendar(
        id,
        'rest-days'
      );

      this.main.days = this.filterCalendar(get(calendar, 'rest-days', []));

      this.setDaysFromCalendar(this.main);
    } catch {
      throw new Error('[components][cards][regions][workCalendarApi]');
    }
  }

  private async initMergedCalendar(id: string) {
    try {
      const days = await IdmServiceDomains.getDomainRestDays({ id });
      this.merged.days = this.filterInheritDays(days);
      this.setDaysFromCalendar(this.merged);
    } catch (e) {
      notifyError(e.toString());
    }
  }

  private setDaysFromCalendar(calendar: Calendar) {
    const restDays = calendar.days;
    calendar.weekWeekend = restDays.filter((day) => day.numDayOfWeek);
    calendar.holidays = restDays.filter(
      (day) => !day.numDayOfWeek && !day.workDay
    );
    calendar.holidays = this.filterCalendar(calendar.holidays);
    calendar.workWeekend = restDays.filter(
      (day) => !day.numDayOfWeek && day.workDay
    );
  }

  private filterInheritDays(calendar: RestDay[]) {
    return calendar.filter(
      (day) => !this.main.days.some((mainDay: RestDay) => mainDay.id === day.id)
    );
  }

  private filterCalendar(calendar: RestDay[]): RestDay[] {
    return calendar.sort((after: any, before: any) =>
      after.longDate > before.longDate ? 1 : -1
    );
  }
}

declare interface Calendar {
  days: RestDay[];
  holidays: RestDay[];
  weekWeekend: RestDay[];
  workWeekend: RestDay[];
}
</script>
