import { Component, PropSync, Prop, Watch, Vue } from 'vue-property-decorator';
import isArray from 'lodash/isArray';
import { convertDateFromTimestamp } from '@utils/format-date';
import { DateFormat } from '@constants/utils/format-date';
import difference from 'lodash/difference';

@Component({})
export default class BaseProductionCalendar extends Vue {
  [key: string]: any;

  @PropSync('week', {
    default: null,
  })
  weekWeekend: RestDay[] | null;

  @PropSync('holid', {
    default: null,
  })
  holidays: RestDay[] | null;

  @PropSync('work', {
    default: null,
  })
  workWeekend: RestDay[] | null;

  @PropSync('hasCalendar', {
    default: false,
  })
  calendar: boolean;

  @Prop({
    default: '',
  })
  title: string;

  @Prop({
    default: false,
  })
  readonly: boolean;

  @Prop({
    default: false,
  })
  edit: boolean;

  @Watch('week')
  private onWeekChanged(val: RestDay[]): void {
    if (val) {
      this.prepareWeekWeekend(val);
    }
  }

  @Watch('holid')
  private onHolidChanged(val: RestDay[]): void {
    if (val) {
      const calendar = this.prepareCalendar(val);

      this.selectedHolidays?.splice(0, this.selectedHolidays.length);
      this.selectedHolidays?.push(...calendar);
    }
  }

  @Watch('work')
  private onWorkChanged(val: RestDay[]): void {
    if (val) {
      const calendar = this.prepareCalendar(val);

      this.selectedWorkWeekend?.splice(0, this.selectedWorkWeekend.length);
      this.selectedWorkWeekend?.push(...calendar);
    }
  }

  protected weekDays: string[] = [
    'Понедельник',
    'Вторник',
    'Среда',
    'Четверг',
    'Пятница',
    'Суббота',
    'Воскресенье',
  ];

  protected loading = false;

  protected tableReadOnly = true;

  protected oldRestDays: (string | undefined)[] = [];

  protected days: Days | null = null;

  protected selectedWeekWeekend: (string | undefined)[] | null = [];

  protected selectedHolidays: string[] = [];

  protected selectedWorkWeekend: string[] = [];

  protected get restDays() {
    return [
      ...(Array.isArray(this.weekWeekend) ? this.weekWeekend : []),
      ...(Array.isArray(this.holidays) ? this.holidays : []),
      ...(Array.isArray(this.workWeekend) ? this.workWeekend : []),
    ];
  }

  protected get isButtonDisabled(): boolean {
    return this.oldRestDays
      ? !difference(
          this.restDays.map((day) => day.description),
          this.oldRestDays
        ).length &&
          !difference(
            this.oldRestDays,
            this.restDays.map((day) => day.description)
          ).length
      : true;
  }

  private cancelChange() {
    if (this.days) {
      this.selectedWeekWeekend = this.days.weekWeekend;
      this.selectedHolidays = this.days.holidays;
      this.selectedWorkWeekend = this.days.workWeekend;
      this.tableReadOnly = true;
    }
  }

  private editTable() {
    this.tableReadOnly = false;
    this.oldRestDays = this.restDays.map((day) => day.description);
    this.days = {
      weekWeekend: this.selectedWeekWeekend,
      holidays: this.selectedHolidays,
      workWeekend: this.selectedWorkWeekend,
    };
  }

  private mounted(): void {
    this.init();
  }

  protected addDate(prop: string) {
    if (prop === 'holidays') {
      const calendar = this.prepareDates(this.selectedHolidays, prop);

      this.holidays = this.filterCalendar(calendar);
    }

    if (prop === 'workWeekend') {
      const calendar = this.prepareDates(this.selectedWorkWeekend, prop);

      this.workWeekend = this.filterCalendar(calendar);
    }
  }

  protected dateHandler(value: string[], prop: string) {
    if (isArray(value) && value.length) {
      this[`${prop}`] = this.prepareDates(value, prop);
    } else {
      this[`${prop}`] = [];
    }
  }

  protected weekHandler(value: string[]) {
    if (isArray(value) && value.length) {
      const arr = value.map((val: any) => {
        return {
          name: val,
          description: val,
          numDayOfWeek: this.getDayOfTheWeekNumber(val),
          londDate: 0,
        };
      });
      this.weekWeekend = arr;
    } else {
      this.weekWeekend = [];
    }
  }

  protected prepareDates(dates: string[], prop: string) {
    return dates.map((val: string) => {
      const date: any = {
        name: `date-${val}`,
        description: `date-${val}`,
        longDate: Date.parse(`${val} 00:00:00`) / 1000,
        workDay: prop === 'workWeekend',
      };
      return date;
    });
  }

  private getDayOfTheWeekNumber(val: keyof typeof WeekDays): number {
    return WeekDays[val];
  }

  private save(): void {
    this.$emit('saveCalendar', this.restDays);
    this.tableReadOnly = true;
  }

  private prepareWeekWeekend(val: RestDay[]) {
    this.selectedWeekWeekend = val.map((day) => {
      return day.name;
    });
  }

  private prepareCalendar(val: RestDay[]) {
    return val.map((day) => {
      return String(
        convertDateFromTimestamp(
          day.longDate as number,
          DateFormat.yearMonthDay
        )
      );
    });
  }

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

  private init(): void {
    this.prepareWeekWeekend(this.weekWeekend || []);
    this.selectedHolidays = this.prepareCalendar(this.holidays || []);
    this.selectedWorkWeekend = this.prepareCalendar(this.workWeekend || []);
  }
}

enum WeekDays {
  'Понедельник' = 2,
  'Вторник' = 3,
  'Среда' = 4,
  'Четверг' = 5,
  'Пятница' = 6,
  'Суббота' = 7,
  'Воскресенье' = 1,
}

declare interface RestDay {
  name?: string;
  description?: string;
  numDayOfWeek?: number;
  longDate?: number;
  workDay?: boolean;
}

declare interface Days {
  weekWeekend: (string | undefined)[] | null;
  holidays: string[];
  workWeekend: string[];
}
