import { ResponsiveSize, ResponsiveUIHelper } from '@dvn/alaca/utils/ui';
import { SingleChoiceField, SingleChoiceFieldOption } from '@dvn/core/doldurma/src/fields/single-choice';
import { TextField } from '@dvn/core/doldurma/src/fields/text';
import { ConcealerConditional, Equal } from '@dvn/core/doldurma/src/interceptors/concealers/ConcealerGenericRule';
import { capitalize } from '@dvn/core/util/string';
import { User } from '@dvn/kimlik/api/models';
import { generateAvailabilities, getTimeFrameOfAvailabilities } from '@dvn/takvim/components/utils';
import { Component, Element, Event, h, Host, Prop, State } from '@stencil/core';
import moment from 'moment-timezone';
import { DvnDataProvider } from "@dvn/core/providers/DvnDataProvider";
import { DvnMemberDataAdapter } from "@dvn/core/adapters/DvnMemberDataAdapter";
import { DataTransferField } from "@dvn/core/doldurma/src/fields/query-include/data-transfer-field";
const meetingLocationTypes = [
  {
    name: 'Custom',
    value: 'custom',
  },
  {
    name: 'Jitsi Meet',
    value: 'jitsi',
  },
  {
    name: 'Zoom',
    value: 'zoom',
  },
];
const formErrors = (error) => {
  if (!error)
    return [];
  // TODO show proper error messages from apiSozluk
  return [
    capitalize(`${error.data.message.split('-').join(' ')}.`, false),
  ];
};
export class TakvimAvailableTimePicker {
  constructor() {
    this.meetingsByMeetingTypes = {};
    /**
     * Raw availabilities fetched from the api.
     */
    this.availabilities = [];
    this.meetingLocationType = 'jitsi';
    this.meetingLocation = '';
    this.isProgressing = true;
    this.weekStartDay = 'monday';
    this.onSizeChange = (size) => {
      this.size = size;
      this.selectedTime = undefined;
      if (this.isMobileUI()) {
        // reset the date otherwise the slot list dialog will pop when switched to mobile
        this.selectedDate = undefined;
      }
      else {
        // set the date otherwise the slot list will keep showing progress
        this.selectedDate = new Date();
      }
    };
    this.isMobileUI = () => this.size < ResponsiveSize.Small;
    this.formFields = () => {
      const { calendarConfig, guests, guestMetadata, meetingsByMeetingTypes, meetingTypes, selectedTime, userSettings, strings, } = this;
      const isCustom = !(selectedTime === null || selectedTime === void 0 ? void 0 : selectedTime.availabilityId);
      const authPlatforms = userSettings.authPlatforms;
      let maxFieldCount = isCustom ? 2 : 0;
      const fields = [];
      const availableMeetingTypes = meetingTypes === null || meetingTypes === void 0 ? void 0 : meetingTypes.filter(meetingType => {
        var _a;
        return ((((_a = meetingsByMeetingTypes[meetingType.id]) === null || _a === void 0 ? void 0 : _a.length) || 0) < meetingType.maxCount);
      });
      calendarConfig.guestDefinitions.forEach((guestDefinition, i) => {
        // TODO use the 'membershipFieldIdInTable' in guestDefinition for the relational guests
        const dataConfig = this.dataConfigs.find(dataConfig => dataConfig._id === guestDefinition.tableId);
        const guestIndex = guestMetadata.findIndex(gm => gm.membershipConfigId === guestDefinition.tableId);
        const guest = guests[guestIndex];
        fields.push(new SingleChoiceField('guest_' + guestDefinition.tableId + '_' + i, i === 0 ? strings.guests : '', undefined, '', 'select', capitalize(dataConfig.roleName)).setDataProvider(new DvnDataProvider(this.apiData, guestDefinition.tableId, {}, guest ? [{ user: guest }] : [], {
          fields: [
            { fieldId: 'email' },
            { fieldId: 'firstName' },
            { fieldId: 'lastName' },
          ]
        })).setDataAdapter(new DvnMemberDataAdapter(true))
          .setValue(guest === null || guest === void 0 ? void 0 : guest._id)
          .setDisabled(!!guest)
          .setRequired(guestDefinition.minCount > 0));
      });
      if (meetingTypes && meetingTypes.length > 0) {
        maxFieldCount += 1;
        fields.push(new SingleChoiceField('meetingType', strings.selectSession, availableMeetingTypes.map(meetingType => new SingleChoiceFieldOption(meetingType.name, meetingType.id)), '', 'select').setErrorTitle('Session').require());
      }
      const meetingLocationTypesLanguage = meetingLocationTypes.map(meetingType => ({
        name: strings[meetingType.value],
        value: meetingType.value,
      }));
      fields.push(...[
        new SingleChoiceField('locationType', strings.location, meetingLocationTypesLanguage
          // filter out the location types if user doesn't have the corresponding auth platform (zoom)
          .filter(locationType => {
          if (locationType.value === 'custom' || locationType.value === 'jitsi') {
            return true;
          }
          return !!authPlatforms.some(authPlatform => authPlatform.id === locationType.value);
        })
          .map(locationType => new SingleChoiceFieldOption(locationType.name, locationType.value)), '', 'select').setValue('jitsi')
          .setVisibility(isCustom)
          .require(),
        new TextField('location', strings.meetingLocation)
          .addInterceptor('onFormChange', new ConcealerConditional(new Equal('locationType', 'custom')))
          .require()
          .hide()
      ]);
      return { fields, maxFieldCount };
    };
    this.onSelectTime = async (e) => {
      this.selectedTime = e.detail;
      const showMeetingDetailsForm = !!this.selectedDate && !!this.selectedTime;
      if (showMeetingDetailsForm && !this.meetings && this.meetingTypes) {
        // get the meetings of the users to filter out the meeting types based on the number of meetings they have
        const { viewedUserId, calendarConfigId, userId } = this;
        this.isProgressing = true;
        const meetings = await this.apiTakvim.getMeetingsOfUser(calendarConfigId, [userId, viewedUserId]).catch(e => {
          this.error = e;
        }).finally(() => this.isProgressing = false);
        if (!meetings)
          return;
        this.meetings = meetings.results;
        const meetingsByMeetingTypes = {};
        this.meetings.forEach(meeting => {
          if (meetingsByMeetingTypes[meeting.meetingType]) {
            meetingsByMeetingTypes[meeting.meetingType].push(meeting);
          }
          else {
            meetingsByMeetingTypes[meeting.meetingType] = [meeting];
          }
        });
        this.meetingsByMeetingTypes = meetingsByMeetingTypes;
      }
    };
    this.onSubmitForm = async (event) => {
      const data = event.detail.values;
      const { location, locationType, meetingType } = data;
      const { startHour, endHour, availabilityId } = this.selectedTime;
      const guestsObject = {};
      const guestsMetadataObject = {};
      Object.keys(data).forEach(fieldId => {
        if (fieldId.startsWith('guest_')) {
          // this is a guest selection in the form. the value is the user id
          const [_, membershipConfigId, index] = fieldId.split('_');
          guestsMetadataObject[index] = { membershipConfigId };
          guestsObject[index] = User.generateRef(data[fieldId]);
        }
      });
      const meeting = {
        locations: [{
            address: location,
            type: locationType,
          }],
        meetingType,
        startDate: startHour.toISOString(),
        endDate: endHour.toISOString(),
        // guests: [
        //   User.generateRef(this.viewedUserId),
        //   User.generateRef(this.userId),
        // ],
        guests: Object.values(guestsObject),
        guestMetadata: Object.values(guestsMetadataObject),
        createdBy: User.generateRef(this.userId),
        status: 'active',
        calendar: { _ref: 'takvim-calendar-configs', _id: this.calendarConfigId },
      };
      if (availabilityId) {
        meeting.availability = {
          _ref: 'takvim-availabilities',
          _id: availabilityId
        };
      }
      this.createMeetingError = undefined;
      this.isProgressing = true;
      const createMeetingResponse = await this.apiTakvim.createMeeting(meeting).catch(e => {
        this.createMeetingError = e;
      }).finally(() => this.isProgressing = false);
      if (!createMeetingResponse)
        return;
      this.meetings = undefined;
      this.selectedTime = undefined;
      this.selectedDate = new Date(this.selectedDate.toISOString());
      this.createMeeting.emit(Object.assign(Object.assign({}, createMeetingResponse), meeting));
    };
  }
  async componentWillLoad() {
    this.uiHelper = new ResponsiveUIHelper(this.el, this.onSizeChange);
    this.size = ResponsiveUIHelper.getSize(this.el.parentElement.clientWidth);
  }
  async componentDidLoad() {
    const { viewedUserId, calendarConfigId } = this;
    const calendarConfig = await this.apiTakvim.getCalendarConfig(calendarConfigId).catch(e => {
      this.error = e;
    });
    if (!calendarConfig)
      return;
    this.calendarConfig = calendarConfig;
    // get all data configs that are used in the calendar config
    // this is needed to query the guests and properly display them in the guest selection
    const promises = [];
    calendarConfig.guestDefinitions.forEach(guestDefinition => {
      promises.push(this.apiData.get('data-configs', guestDefinition.tableId, { fields: new DataTransferField('fields') }));
      if (guestDefinition.membershipFieldIdInTable) {
        promises.push(this.apiData.get('data-configs', guestDefinition.membershipFieldIdInTable, { fields: new DataTransferField('fields') }));
      }
    });
    const dataConfigs = await Promise.all(promises);
    if (!dataConfigs)
      return;
    this.dataConfigs = dataConfigs;
    const availabilities = await this.apiTakvim.getAvailabilitiesOfUser(viewedUserId).catch(e => {
      this.error = e;
    }).finally(() => this.isProgressing = false);
    if (!availabilities)
      return;
    this.availabilities = availabilities.results;
    // get the earliest start time and latest end time of the availabilities to fetch the unavailabilities for that time period
    const { startDate, endDate } = getTimeFrameOfAvailabilities(availabilities.results);
    if (startDate && endDate) {
      const unavailabilitiesOfOtherUser = await this.apiTakvim.getUnavailabilitiesOfUser(calendarConfigId, viewedUserId, startDate.toISOString(), endDate.toISOString()).catch(e => {
        this.error = e;
      }).finally(() => this.isProgressing = false);
      if (!unavailabilitiesOfOtherUser)
        return;
      // console.log('unavailabilitiesOfOtherUser', unavailabilitiesOfOtherUser);
      unavailabilitiesOfOtherUser.results.filter(un => un.reason.source === 'google-calendar').forEach(un => {
        console.log(un.startDate);
      });
      this.generatedAvailabilities = generateAvailabilities(availabilities.results, unavailabilitiesOfOtherUser.results);
    }
    else {
      this.generatedAvailabilities = generateAvailabilities(availabilities.results, []);
    }
    if (!this.isMobileUI()) {
      // invoke onSelectDate for generating initial slots
      if (this.generatedAvailabilities.length > 0) {
        // focus on the date with the first availability
        this.selectedDate = new Date(this.generatedAvailabilities[0].startDate);
      }
      else {
        // focus on today
        this.selectedDate = new Date();
      }
    }
  }
  render() {
    const { calendarConfigId, calendarConfig, createMeetingError, generatedAvailabilities, isProgressing, meetingTypes, selectedDate, selectedTime, strings, userId, membershipConfigId, viewedUserId, viewedUserMembershipConfigId, weekStartDay, } = this;
    if (!calendarConfig) {
      return null;
    }
    const showMeetingDetailsForm = !!selectedDate && !!selectedTime;
    const { fields: meetingDetailsFormFields, maxFieldCount } = this.formFields();
    const minFormHeight = `${Math.max(maxFieldCount * 100, (meetingTypes === null || meetingTypes === void 0 ? void 0 : meetingTypes.length) > 0 ? 200 : 120)}px`;
    const timeZone = this.userSettings.timeZone;
    const hourFormat = this.userSettings.timeFormat === '12-hour' ? 'hh:mm A' : 'HH:mm';
    const location = this.meetingLocationType === 'custom' ? this.meetingLocation : `${strings[this.meetingLocationType]}`;
    const dialogTitle = `${moment(selectedDate).tz(timeZone).format('DD MMMM')}, ${moment(selectedTime === null || selectedTime === void 0 ? void 0 : selectedTime.startHour).tz(timeZone).format(hourFormat)} - ${moment(selectedTime === null || selectedTime === void 0 ? void 0 : selectedTime.endHour).tz(timeZone).format(hourFormat)} ${timeZone} - ${location}`;
    if (this.isMobileUI()) {
      return (h(Host, { class: "d-flex mobile" },
        h("dvn-card", { class: "date-picker-container", bodyLeaned: true, leaned: true, elevation: 0, width: "100%" },
          h("div", { class: "d-flex justify-content-center" },
            h("dvn-date-picker", { embedded: true, leaned: true, value: generatedAvailabilities === null || generatedAvailabilities === void 0 ? void 0 : generatedAvailabilities.map(ca => new Date(ca.startDate)), onChange: (e) => this.selectedDate = e.detail, strings: strings, weekStartDay: weekStartDay }))),
        h("dvn-dialog", { class: "confirmation-dialog", shown: !!selectedDate || showMeetingDetailsForm, onDismiss: (e) => {
            e.preventDefault();
            e.stopImmediatePropagation();
            this.createMeetingError = undefined;
            if (selectedTime) {
              this.selectedTime = undefined;
            }
            else {
              this.selectedDate = undefined;
            }
          }, raw: !!selectedDate && !showMeetingDetailsForm, title: dialogTitle },
          (selectedDate && !showMeetingDetailsForm) &&
            h("takvim-available-time-picker-selected-day", { availabilities: this.generatedAvailabilities, calenderConfig: calendarConfig, selectedDate: selectedDate, userId: userId, membershipConfigId: membershipConfigId, userSettings: this.userSettings, viewedUserId: viewedUserId, viewedUserMembershipConfigId: viewedUserMembershipConfigId, calendarConfigId: calendarConfigId, apiTakvim: this.apiTakvim, onSelectTime: this.onSelectTime, strings: strings }),
          showMeetingDetailsForm &&
            h("div", { class: "ml-3 mr-3 mt-3 mb-2" },
              h("doldurma-form", { key: `${selectedTime === null || selectedTime === void 0 ? void 0 : selectedTime.startHour}-${selectedTime === null || selectedTime === void 0 ? void 0 : selectedTime.endHour}`, fields: meetingDetailsFormFields, onSubmit: this.onSubmitForm, submitButtonLabel: strings.scheduleMeeting, progressing: isProgressing, formErrors: formErrors(createMeetingError), minHeight: minFormHeight, width: '100%' })))));
    }
    return (h(Host, { class: "d-flex desktop" },
      h("dvn-date-picker", { embedded: true, leaned: true, value: generatedAvailabilities === null || generatedAvailabilities === void 0 ? void 0 : generatedAvailabilities.map(ca => new Date(ca.startDate)), highlightedDay: this.selectedDate, onChange: (e) => this.selectedDate = e.detail, strings: strings, weekStartDay: weekStartDay }),
      h("takvim-available-time-picker-selected-day", { availabilities: this.generatedAvailabilities, calenderConfig: calendarConfig, selectedDate: selectedDate, userId: userId, membershipConfigId: membershipConfigId, userSettings: this.userSettings, viewedUserId: viewedUserId, viewedUserMembershipConfigId: viewedUserMembershipConfigId, calendarConfigId: calendarConfigId, apiTakvim: this.apiTakvim, onSelectTime: this.onSelectTime, strings: strings }),
      h("dvn-dialog", { class: "confirmation-dialog", shown: showMeetingDetailsForm, onDismiss: (e) => {
          e.preventDefault();
          e.stopImmediatePropagation();
          this.selectedTime = undefined;
          this.createMeetingError = undefined;
        }, minHeight: '240px', title: dialogTitle },
        h("doldurma-form", { key: `${selectedTime === null || selectedTime === void 0 ? void 0 : selectedTime.startHour}-${selectedTime === null || selectedTime === void 0 ? void 0 : selectedTime.endHour}`, fields: meetingDetailsFormFields, onSubmit: this.onSubmitForm, submitButtonLabel: strings.scheduleMeeting, progressing: isProgressing, formErrors: formErrors(createMeetingError), minHeight: minFormHeight, width: '100%' }))));
  }
  static get is() { return "takvim-available-time-picker"; }
  static get originalStyleUrls() { return {
    "$": ["takvim-available-time-picker.scss"]
  }; }
  static get styleUrls() { return {
    "$": ["takvim-available-time-picker.css"]
  }; }
  static get properties() { return {
    "userId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      },
      "attribute": "user-id",
      "reflect": false
    },
    "membershipConfigId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      },
      "attribute": "membership-config-id",
      "reflect": false
    },
    "userSettings": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "UserSettings",
        "resolved": "UserSettings",
        "references": {
          "UserSettings": {
            "location": "import",
            "path": "@dvn/kimlik/api/models/UserSettings"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      }
    },
    "viewedUserId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      },
      "attribute": "viewed-user-id",
      "reflect": false
    },
    "viewedUserMembershipConfigId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      },
      "attribute": "viewed-user-membership-config-id",
      "reflect": false
    },
    "calendarConfigId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      },
      "attribute": "calendar-config-id",
      "reflect": false
    },
    "meetingTypes": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "MeetingType[]",
        "resolved": "MeetingType[]",
        "references": {
          "MeetingType": {
            "location": "import",
            "path": "@dvn/takvim/models/MeetingType"
          }
        }
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": ""
      }
    },
    "weekStartDay": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "'monday' | 'saturday' | 'sunday'",
        "resolved": "\"monday\" | \"saturday\" | \"sunday\"",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      },
      "attribute": "week-start-day",
      "reflect": false,
      "defaultValue": "'monday'"
    },
    "apiTakvim": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "TakvimApi",
        "resolved": "TakvimApi",
        "references": {
          "TakvimApi": {
            "location": "import",
            "path": "@dvn/takvim/api/takvimApi"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      }
    },
    "apiData": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "DataApi",
        "resolved": "DataApi",
        "references": {
          "DataApi": {
            "location": "import",
            "path": "@dvn/core/api"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      }
    },
    "strings": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "TakvimAvailableTimePickerI18n",
        "resolved": "TakvimAvailableTimePickerI18n",
        "references": {
          "TakvimAvailableTimePickerI18n": {
            "location": "import",
            "path": "@dvn/takvim/components/takvim-available-time-picker/i18n"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      }
    },
    "guests": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "Ref[] | User[]",
        "resolved": "Ref[] | User[]",
        "references": {
          "Ref": {
            "location": "import",
            "path": "@dvn/core/models/ref"
          },
          "User": {
            "location": "import",
            "path": "@dvn/kimlik/api/models"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      }
    },
    "guestMetadata": {
      "type": "unknown",
      "mutable": false,
      "complexType": {
        "original": "{\n    membershipConfigId: string\n  }[]",
        "resolved": "{ membershipConfigId: string; }[]",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": ""
      }
    }
  }; }
  static get states() { return {
    "calendarConfig": {},
    "dataConfigs": {},
    "meetings": {},
    "meetingsByMeetingTypes": {},
    "availabilities": {},
    "generatedAvailabilities": {},
    "selectedDate": {},
    "selectedTime": {},
    "meetingLocationType": {},
    "meetingLocation": {},
    "isProgressing": {},
    "error": {},
    "createMeetingError": {},
    "size": {}
  }; }
  static get events() { return [{
      "method": "createMeeting",
      "name": "createMeeting",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": ""
      },
      "complexType": {
        "original": "any",
        "resolved": "any",
        "references": {}
      }
    }]; }
  static get elementRef() { return "el"; }
}
