<template lang="pug">
  base-modal(
    v-model="value",
    :title="!selectedEventData.id ? 'Запись на прием' : 'Изменение записи'",
    draggable,
    hide-overlay
  )
    .event-form.flex.flex-col.gap-y-6.pt-8
      .flex.flex-col.gap-y-8
        base-select(
          v-if="selectedEventData.id"
          v-model="status",
          :items="statusesList",
          label="Статус приема"
        )
        base-input(
          v-else,
          disabled,
          v-model="status.label",
          label="Статус приема",
          outlined
        )
        base-select(
          :items="ownersList",
          v-model="employees.employee",
          placeholder="Выберите сотрудника"
          label="Сотрудник"
        )
        base-select(
          :items="membersList",
          v-model="members.person",
          placeholder="Выберите клиента",
          label="Клиент"
        )
      .flex.gap-x-4
        base-input(
          v-model="eventDate",
          label="Дата",
          type="date",
          outlined
        )
        .flex.gap-x-2.items-center.justify-between
          base-input(
            type="time",
            v-model="startTime",
            label="Начало",
            outlined
          )
          span.mt-4 —
          base-input(
            type="time",
            v-model="endTime",
            label="Конец",
            outlined
          )
      q-btn.create-button(
        v-if="!selectedEventData.id",
        label="Создать событие",
        no-caps,
        color="primary",
        padding="10px 22px",
        :disabled="disabledCreateButton",
        @click="sendEventData",
      )
      q-btn.update-button(
        v-else,
        label="Сохранить",
        no-caps,
        color="primary",
        padding="10px 22px",
        :disabled="disabledUpdateButton",
        @click="updateEventData",
      )
</template>

<script>
import TheNotificationProvider from "@/components/Notifications/TheNotificationProvider";
import { addNotification } from "@/components/Notifications/notificationContext";
import { fetchWrapper } from "@/shared/fetchWrapper.js";
import BaseInput from "@/components/base/BaseInput.vue";
import BaseSelect from "@/components/base/BaseSelect.vue";
import * as moment from "moment/moment";
import BaseModal from "@/components/base/BaseModal.vue";
import { v_model } from "@/shared/mixins/v-model";
import { statusesConfig } from "@/pages/calendar/utils/statusesConfig";

export default {
  name: "FormChangeEvent",
  components: {
    BaseModal,
    BaseSelect,
    BaseInput,
    TheNotificationProvider,
  },
  mixins: [v_model],
  //emits: ["clear-selected-event-data", "close-change-form"],
  emits: ["clear-event-data"],
  props: {
    //closeForm: Function,
    selectedEventData: {
      type: Object,
      default() {
        return {};
      },
    },
    timeInformation: {
      type: Object,
      default() {
        return {};
      },
    },
    currentDate: {
      type: Object,
      default() {
        return {};
      },
    },
  },
  data() {
    return {
      EMPLOYEE_TYPE: "owner",
      MEMBER_TYPE: "primary",
      EVENT_KIND: "Прием",
      eventData: {},
      startTime: "",
      endTime: "",
      members: {},
      employees: {},
      eventDate: Date,
      status: { label: "Планируется прием", id: null },
      id: null,
      //ifClearedForm: true,
      membersData: [],
      ownersData: [],
      WORKING_STATUS: "WORKS",
    };
  },
  computed: {
    ownersList() {
      if (this.ownersData) {
        let filteredArray = [];
        this.ownersData.forEach((elem) => {
          filteredArray.push({
            id: elem.id,
            label: this.trimOwnerName(
              elem.last_name,
              elem.first_name,
              elem.patronymic
            ),
          });
        });
        return filteredArray;
      }
      return [];
    },
    membersList() {
      if (this.membersData) {
        let filteredArray = [];
        this.membersData.forEach((elem) => {
          filteredArray.push({
            id: elem.id,
            label: this.trimMemberName(
              elem.last_name,
              elem.first_name,
              elem.patronymic
            ),
          });
        });
        return filteredArray;
      }
      return [];
    },
    statusesList() {
      let filteredArray = [];
      statusesConfig.forEach((elem) => {
        filteredArray.push({
          id: elem.id,
          label: elem.label,
        });
      });
      return filteredArray;
    },
    disabledCreateButton() {
      if (
        this.eventDate &&
        this.startTime &&
        this.endTime &&
        this.members.person.label &&
        this.employees.employee.label &&
        this.status.label
      ) {
        return false;
      }
      return true;
    },
    disabledUpdateButton() {
      let start = moment(this.selectedEventData.start);
      let end = moment(this.selectedEventData.end);
      if (
        moment(this.eventDate).format("YYYY-MM-DD") ===
          start.format("YYYY-MM-DD") &&
        this.startTime === start.format("HH:mm") &&
        this.endTime === end.format("HH:mm") &&
        this.findStatus(this.status.label) === this.selectedEventData.status &&
        this.employees.employee.id ===
          this.personId(this.selectedEventData.employees, "employee") &&
        this.members.person.id ===
          this.personId(this.selectedEventData.members, "person")
      ) {
        return true;
      }
      if (!this.eventDate) return true;
      return false;
    },
    startDate() {
      return this.selectedEventData.start
        ? new Date(this.selectedEventData.start)
        : this.currentDate.toDate();
    },
    endDate() {
      return this.selectedEventData.end
        ? new Date(this.selectedEventData.end)
        : this.currentDate.toDate();
    },
    eventEmployee() {
      if (this.selectedEventData.employees) {
        let foundEmployee = this.selectedEventData.employees.find(
          ({ role }) => role === this.EMPLOYEE_TYPE
        );
        let {
          employee: { id, last_name, first_name, patronymic },
          ...rest
        } = foundEmployee;
        return {
          employee: {
            id: id,
            label: this.trimOwnerName(last_name, first_name, patronymic),
          },
          id: rest?.id || null,
          role: rest?.role || this.EMPLOYEE_TYPE,
        };
      }
      return {
        employee: {
          id: null,
          label: "",
        },
        role: this.EMPLOYEE_TYPE,
      };
    },
    eventMember() {
      if (this.selectedEventData.members) {
        let foundMember = {};
        if (this.selectedEventData.members.length > 1) {
          foundMember = this.selectedEventData.members.find(
            ({ role }) => role === this.MEMBER_TYPE
          );
        } else foundMember = this.selectedEventData.members[0];
        let {
          person: { id, last_name, first_name, patronymic },
          ...rest
        } = foundMember;
        return {
          person: {
            id: id,
            label: this.trimMemberName(last_name, first_name, patronymic),
          },
          id: rest.id,
          role: rest?.role || this.MEMBER_TYPE,
        };
      }
      return {
        person: {
          id: null,
          label: "",
        },
        role: this.MEMBER_TYPE,
      };
    },

    eventId() {
      return this.selectedEventData.id ? this.selectedEventData.id : "";
    },
    eventStatus() {
      return this.selectedEventData.status
        ? {
            label: statusesConfig.find(
              (e) => e.value === this.selectedEventData.status
            ).label,
            id: statusesConfig.find(
              (e) => e.value === this.selectedEventData.status
            ).id,
          }
        : {
            label: statusesConfig.find((e) => e.value === "PLANNED").label,
            id: 0,
          };
    },
  },
  methods: {
    findStatus(value) {
      return statusesConfig.find((e) => e.label === value)?.value;
    },
    checkTimeLimits(eventTime, scheduleTime, timeType) {
      if (timeType === "start")
        return (
          parseInt(eventTime.split(":")[0]) <
          parseInt(scheduleTime.split(":")[0])
        );
      if (timeType === "end") {
        let firstTime = eventTime.split(":").map((elem) => parseInt(elem));
        let secondTime = scheduleTime.split(":").map((elem) => parseInt(elem));
        if (firstTime[0] === secondTime[0]) return firstTime[1] > secondTime[1];
        else return firstTime[0] > secondTime[0];
      }
    },
    checkTime() {
      let counter = 0;
      let foundedSchedule = {};
      let foundedEmployee = this.ownersData.find(
        (elem) => elem.id === this.employees.employee.id
      );
      if (foundedEmployee)
        foundedSchedule = foundedEmployee.schedules.find(
          (elem) =>
            elem.date === moment(this.eventDate).format("YYYY-MM-DD") &&
            elem.status === this.WORKING_STATUS
        );
      if (!foundedSchedule) {
        this.addErrorNotification(
          "Некорректная дата события",
          `В данный день ${this.employees.employee.label} не работает`
        );
        counter += 1;
        return false;
      }
      if (
        this.checkTimeLimits(
          this.startTime,
          foundedSchedule.start_time,
          "start"
        )
      ) {
        this.addErrorNotification(
          "Некорректное время начала события",
          "Время начала события раньше начала рабочего дня"
        );
        counter += 1;
      }
      if (this.checkTimeLimits(this.endTime, foundedSchedule.end_time, "end")) {
        this.addErrorNotification(
          "Некорректное время окончания события",
          "Время окончания события позже окончания рабочего дня"
        );
        counter += 1;
      }
      if (
        this.checkTimeLimits(this.endTime, foundedSchedule.start_time, "start")
      ) {
        this.addErrorNotification(
          "Некорректное время окончания события",
          "Время окончания события раньше начала рабочего дня"
        );
        counter += 1;
      }
      if (
        this.checkTimeLimits(this.startTime, foundedSchedule.end_time, "end")
      ) {
        this.addErrorNotification(
          "Некорректное время начала события",
          "Время начала события позже окончания рабочего дня"
        );
        counter += 1;
      }
      return counter === 0;
    },
    trimOwnerName(lastName, firstName, patronymic) {
      let checkedFirstName = firstName !== null ? firstName[0] + "." : "";
      let checkedPatronymic = patronymic !== null ? patronymic[0] + "." : "";
      return `${lastName} ${checkedFirstName}${checkedPatronymic}`;
    },
    trimMemberName(lastName, firstName, patronymic) {
      return `${lastName} ${firstName ?? ""} ${patronymic ?? ""}`;
    },
    async sendEventData() {
      if (!this.checkTime()) return;
      this.eventData = {
        start: this.mergeDate(this.eventDate, this.startTime),
        end: this.mergeDate(this.eventDate, this.endTime),
        status: this.findStatus(this.status.label),
        kind: this.EVENT_KIND,
        employees: [
          this.findPerson(this.ownersData, this.employees, "employee"),
        ],
        members: [this.findPerson(this.membersData, this.members, "person")],
      };
      await this.postCreateEvent(this.eventData);
      this.eventData = {};
      this.value = false;
    },
    async updateEventData() {
      if (!this.checkTime()) return;
      if (
        Object.keys(
          this.findPerson(this.ownersData, this.employees, "employee")
        ).length > 0 &&
        Object.keys(this.findPerson(this.membersData, this.members, "person"))
          .length > 0
      ) {
        this.eventData = {
          start: this.mergeDate(this.eventDate, this.startTime),
          end: this.mergeDate(this.eventDate, this.endTime),
          status: this.findStatus(this.status.label),
          employees: [
            this.findPerson(this.ownersData, this.employees, "employee"),
          ],
          members: [this.findPerson(this.membersData, this.members, "person")],
        };
        await this.postUpdateEvent(this.id, this.eventData);
        this.eventData = {};
        this.value = false;
      } else
        this.addErrorNotification(
          "Событие не может быть изменено",
          "Клиент был удален"
        );
    },
    //clearForm() {
    //  if (this.selectedEventData.id) this.$emit("close-change-form");
    //  this.$emit("clear-selected-event-data");
    //  this.closeForm();
    //},
    mergeDate(eventDate, time) {
      let parseTime = time.split(":");
      return moment(eventDate.setHours(parseTime[0], parseTime[1]), 0).format(
        "YYYY-MM-DDTHH:mm:ss"
      );
    },
    findPerson(requestedList, object, field) {
      let foundPerson = requestedList.find(({ id }) => id === object[field].id);
      if (foundPerson) {
        let returnedData = {
          [field]: {
            id: foundPerson.id,
            last_name: foundPerson.last_name,
            first_name: foundPerson.first_name,
            patronymic: foundPerson.patronymic,
            color: foundPerson.color,
          },
          role: object.role,
        };
        if (object.id) returnedData.id = object.id;
        return returnedData;
      }
      return {};
    },
    async postCreateEvent(event) {
      const response = await fetchWrapper.post("registry/event/create/", event);
      if (response.type && response.type === "validation_error") {
        this.addErrorNotification(
          response.errors[0].code,
          response.errors[0].detail
        );
      } else {
        this.addSuccessNotification("Событие успешно создано");
        //this.clearForm();
      }
    },
    async postUpdateEvent(id, event) {
      const response = await fetchWrapper.post(
        `registry/event/${id}/update/`,
        event
      );
      if (response.type && response.type === "validation_error") {
        this.addErrorNotification(
          response.errors[0].code,
          response.errors[0].detail
        );
      } else {
        this.addSuccessNotification("Изменения успешно сохранены");
        //this.clearForm();
      }
    },
    personId(object, field) {
      if (object) {
        let foundPerson = {};
        if (field === "employee") {
          foundPerson = object.find(({ role }) => role === this.EMPLOYEE_TYPE);
        }
        if (field === "person") {
          if (object.length > 1) {
            foundPerson = object.find(({ role }) => role === this.MEMBER_TYPE);
          }
          foundPerson = object[0];
        }
        let {
          [field]: { id },
        } = foundPerson;
        return id;
      }
    },
    addErrorNotification(title, message) {
      addNotification(title, title, message, "error", 5000);
    },
    addSuccessNotification(message) {
      addNotification(new Date().getTime(), message, "", "success", 5000);
    },
    fetchMembersData() {
      fetchWrapper
        .get("general/person/?limit=200")
        .then((res) => this.saveMembersData(res));
    },
    fetchOwnersData() {
      fetchWrapper
        .get(
          `accounts/schedules/?date_after=${this.currentDate
            .clone()
            .subtract(1, "month")
            .format("YYYY-MM-DD")}&date_before=${this.currentDate
            .clone()
            .add(1, "month")
            .format("YYYY-MM-DD")}`
        )
        .then((res) => this.saveOwnersData(res));
    },
    saveOwnersData(res) {
      let serializedList = [];
      if (res.results.length === 0) {
        this.ownersData = [];
        return;
      }
      res.results.forEach((elem) => {
        let foundedElem = serializedList.find(
          (item) => item.id === elem.employee.id
        );
        if (!foundedElem) {
          serializedList.push({
            id: elem.employee.id,
            last_name: elem.employee.last_name,
            first_name: elem.employee.first_name,
            patronymic: elem.employee.patronymic,
            color: elem.employee.color,
            schedules: [
              {
                date: elem.date,
                end_time: elem.end_time?.slice(0, elem.end_time.length - 3),
                start_time: elem.start_time?.slice(
                  0,
                  elem.start_time.length - 3
                ),
                status: elem.status,
                id: elem.id,
              },
            ],
          });
        } else {
          foundedElem.schedules.push({
            date: elem.date,
            end_time: elem.end_time?.slice(0, elem.end_time.length - 3),
            start_time: elem.start_time?.slice(0, elem.start_time.length - 3),
            status: elem.status,
            id: elem.id,
          });
        }
      });
      this.ownersData = serializedList;
    },
    saveMembersData(res) {
      this.membersData = res.results;
    },
  },
  watch: {
    startDate: {
      immediate: true,
      handler(newDate) {
        if (newDate) {
          this.eventDate = newDate;
          this.startTime = moment(newDate).format("HH:mm");
        }
      },
    },
    endDate: {
      immediate: true,
      handler(newDate) {
        if (newDate) {
          this.endTime = moment(newDate).format("HH:mm");
        }
      },
    },
    selectedEventData: {
      immediate: true,
      handler(newDate) {
        if (newDate) {
          this.id = this.eventId;
          this.status = this.eventStatus;
          this.employees = this.eventEmployee;
          this.members = this.eventMember;
        }
      },
    },
    value(newValue) {
      if (newValue === false) this.$emit("clear-event-data");
    },
  },
  mounted() {
    this.fetchOwnersData();
    this.fetchMembersData();
  },
};
</script>

<style lang="sass" scoped>
.event-form
  width: 550px

.form-item
  border-radius: 4px
  width: 344px
  background-color: var(--default-white)

.date-input
  width: 174px
  border-radius: 4px
  background-color: var(--default-white)

.icon
  width: 24px
  height: 24px
  color: var(--font-dark-blue-color)

.close-icon
  color: var(--font-dark-blue-color)
  &:hover
    color: var(--btn-blue-color)

.create-button
  width: 183px

.select
  border: 1.5px solid var(--border-light-grey-color)
  border-radius: 4px

.update-button
  width: 132px
</style>
