import {
  getCurrentMedia
} from "modules/device/media";
import flow from "lodash/flow";
import forkBooking from "modules/fork-booking";
import groupBy from "lodash/groupBy";
import moment from "moment";
import Parsley from "parsleyjs";
import Pikaday from "pikaday";
import Vue from "vue";

export default Vue.extend({

  data: function() {

    return {
      analyticsCall: undefined,
      analyticsName: undefined,
      analyticsType: undefined,
      apiErrorMessage: undefined,
      choices: {
        date: undefined,
        email: undefined,
        firstName: undefined,
        hour: undefined,
        lastName: undefined,
        optin: false,
        people: undefined,
        phone: undefined,
        phonePrefix: "33",
        saleType: undefined,
        title: undefined
      },
      culture: window.JSONendpointSettings.locale,
      datePicker: undefined,
      hours: {
        BREAKFAST: undefined,
        DINER: undefined,
        LUNCH: undefined
      },
      isLoading: true,
      minStep: 0,
      maxStep: 5,
      menuOfferLabel: "",
      numberOfPeople: {
        count: undefined,
        group: undefined,
        normal: undefined
      },
      peopleSelectModel: "",
      restaurantId: undefined,
      reservationData: undefined,
      salesTypes: [],
      step: -1
    };
  },
  filters: {

    formatDate(date, culture) {

      const m = moment(date);

      switch (culture)
      {
        case "en_GB":
          return m.format("MMMM Do");
        default:
          return m.format("Do MMMM");
      }
    },
    formatFullDate(date) {

      return moment(date).format("LL");
    },
    formatHour(hour) {

      return moment(hour).format("HH:mm");
    }
  },
  methods: {

    clearObsoleteData(step) {

      // Clears contact form step choices
      if (step < 4)
      {
        this.choices.email = undefined;
        this.choices.firstName = undefined;
        this.choices.lastName = undefined;
        this.choices.optin = false;
        this.choices.phone = undefined;
        this.choices.phonePrefix = "33";
        this.choices.title = undefined;
      }

      // Clears people selection step choices
      if (step < 3)
      {
        this.choices.people = undefined;
        this.peopleSelectModel = "";
      }

      // Clears hour selection step choices
      if (step < 2)
      {
        this.choices.hour = undefined;
      }

      // Clears date selection step choices
      if (step < 1)
      {
        this.choices.date = undefined;
      }

      // Clears sale type selection step choices
      if (step === 0 && !this.isMobileDevice())
      {
         this.choices.saleType = undefined;
      }
    },
    initBookingTypeStep() {

      this.startLoading();
      forkBooking.getSalesTypes({ idRestaurant: this.restaurantId }).done((response) => {

        if (response.result !== 1)
        {
          console.error("LaFourchette API error", response);
          return;
        }

        this.salesTypes = response.data.sale_type_list;
        if (this.salesTypes.length === 0)
        {
          this.next();
          this.minStep = 1;
        }
        this.stopLoading();
      });
    },
    initDateStep() {

      this.startLoading();
      forkBooking.getDayOpen(this.restaurantId).done(response => {

        if (response.result !== 1)
        {
          console.error("LaFourchette API: unexpected response", response);
          return;
        }

        const selectedSaleType = this.choices.saleType;
        const data = response.data;
        const length = data.length;

        if (selectedSaleType !== undefined && length === 0)
        {
          console.error("LaFourchette API: No data available");
          return;
        }

        const min = length > 0 ? new Date(data[0].date) : new Date();
        const max = length > 0 ? new Date(data[length - 1].date) : undefined;
        const menuOfferLabel = this.menuOfferLabel;

        this.datePicker = new Pikaday({
          bound: false,
          container: this.$refs.datePicker,
          disableWeekends: false,
          field: this.$refs.datePickerInput,
          firstDay: 1,
          i18n: {
            months: window.tabMonthsFull,
            weekdays: window.tabDay,
            weekdaysShort: window.tabDayShort
          },
          maxDate: max,
          minDate: min,
          theme: "pikaday-barriere-dark",
          disableDayFn: date => !this.isDayAvailableForBooking(data, selectedSaleType, date),
          onDraw: instance => {

            data.forEach(day => {

              if (this.isMenuOfferDay(day, selectedSaleType))
              {
                const date = moment(day.date, "YYYY-MM-DD");
                const pickerButton = instance.el.querySelector(`.pika-day[data-pika-year="${date.year()}"][data-pika-month="${date.month()}"][data-pika-day="${date.date()}"]`);

                if (pickerButton !== null)
                {
                  pickerButton.dataset.menuOfferLabel = menuOfferLabel;
                  pickerButton.classList.add("is-menu-offer");
                }
              }
            });
          },
          onSelect: this.onDateSelect
        });
        if (this.choices.date !== undefined)
        {
          /*
           * NOTE: You can optionally pass a boolean as the second parameter to prevent triggering of the onSelect
           * callback (true), allowing the date to be set silently
           */
          this.datePicker.setDate(this.choices.date, true);
        }
        this.stopLoading();
      });
    },
    initHourStep() {

      this.startLoading();
      forkBooking.getHourOpen(this.restaurantId, this.choices.date).done(response => {

        if (response.result !== 1)
        {
          console.error("LaFourchette API: unexpected response", response);
          return;
        }

        const { saleType } = this.choices;

        const processHours = flow(
          (x) => x.filter(h => (saleType === undefined || this.isSaleTypeHour(h, saleType))),
          (x) => groupBy(x, "lunch_type"));

        const hours = processHours(response.data);

        this.hours.BREAKFAST = hours.BREAKFAST || undefined;
        this.hours.DINER = hours.DINER || undefined;
        this.hours.LUNCH = hours.LUNCH || undefined;
        this.stopLoading();
      });
    },
    initPeopleStep() {

      this.startLoading();
      forkBooking.getGroupAvailibility(this.restaurantId, this.choices.hour.datetime).done(response => {

        if (response.result !== 1)
        {
          console.error("LaFourchette API: unexpected response", response);
          return;
        }

        const { saleType } = this.choices;

        const processNbPeople = flow(
          x => x.filter(p => (saleType === undefined || this.isSaleTypePeopleAvailability(p, saleType))),
          x => ({ data: groupBy(x, "is_group"), count: x.length }));

        const nbPeople = processNbPeople(response.data);

        this.numberOfPeople.count = nbPeople.count;
        this.numberOfPeople.group = nbPeople.data["true"] || undefined;
        this.numberOfPeople.normal = nbPeople.data["false"] || undefined;
        this.stopLoading();
      });
    },
    initPersonInformationStep() {

      const parsley = new Parsley.Factory(this.$el, {

        // NOTE: see http://parsleyjs.org/doc/annotated-source/defaults.html#section-18
        classHandler: (ParsleyField) => {

          const $el = ParsleyField.$element;

          if ($el.hasClass('js-text-field'))
          {
            return $el.closest('.c-lafourchettebooking-form-textfield');
          }
          if ($el.hasClass("js-title-radio"))
          {
            return $el.closest(".c-lafourchettebooking-form-radio");
          }
          return $el;
        },
        errorsContainer : (ParsleyField) => {

          const $el = ParsleyField.$element;

          if ($el.hasClass('js-phone-field'))
          {
            return $el.closest(".c-lafourchettebooking-form-row");
          }
          return $el.parent();
        },
        errorClass: 'is-invalid',
        successClass: 'is-valid'
      });
      parsley.on("form:success", () => this.onSubmit());
      parsley.on("form:submit", () => false);
    },
    isDayAvailableForBooking(laFourchetteDays, saleType, date) {

      const currentFormattedDate = moment(date);
      const day = laFourchetteDays.find(day => day.date === currentFormattedDate.format("YYYY-MM-DD"));

      return saleType === undefined || this.isSaleTypeDay(day, saleType);
    },
    isMenuOffer(saleType) {

      if (saleType === undefined)
      {
        return false;
      }
      return Boolean(saleType.is_menu);
    },
    isMenuOfferDay(day, saleType) {

      return this.isMenuOffer(saleType) && this.isSaleTypeDay(day, saleType);
    },
    isMenuOfferHour(hour, saleType) {

      return this.isMenuOffer(saleType) && this.isSaleTypeHour(hour, saleType);
    },
    isMobileDevice() {

      const media = getCurrentMedia(window);

      return (media !== undefined && media.type === "mobile" && media.orientation === "portrait");
    },
    isSaleTypeDay(day, saleType) {

      return (day !== undefined && saleType !== undefined && day.id_sale_type_list.indexOf(saleType.id_sale_type) > -1);
    },
    isSaleTypeHour(hour, saleType) {

      return (hour !== undefined && saleType !== undefined && hour.id_sale_type_list.indexOf(saleType.id_sale_type) > -1);
    },
    isSaleTypePeopleAvailability(peopleAvailability, saleType) {

      return (peopleAvailability !== undefined && saleType !== undefined && peopleAvailability.id_sale_type_list.indexOf(saleType.id_sale_type) > -1);
    },
    goToStep(step) {

      if (step !== this.step && (step >= this.minStep && step <= this.maxStep))
      {
        this.apiErrorMessage = undefined;

        // Destroys date picker instance if it exists
        if (this.datePicker !== undefined)
        {
          this.datePicker.destroy();
          this.datePicker = undefined;
        }

        // Clears obsolete data if the user navigates backwards
        if (step < this.step)
        {
          this.clearObsoleteData(step);
        }

        // Saves current step
        this.step = step;

        // Booking type step
        if (step === 0)
        {
          this.initBookingTypeStep();
        }

        // Date selection step
        if (step === 1)
        {
          this.initDateStep();
        }

        // Hour selection step
        if (step === 2)
        {
          this.initHourStep();
        }

        // People selection step
        if (step === 3)
        {
          this.initPeopleStep();
        }

        // Personal information step
        if (step === 4)
        {
          this.initPersonInformationStep();
        }
      }
    },
    prev() {

      this.goToStep(this.step - 1);
    },
    next() {

      this.goToStep(this.step + 1);
    },
    onDateSelect(date) {

      this.choices.date = date;
      if (!this.isMobileDevice())
      {
        this.next();
      }
    },
    onHourSelect(hour) {

      this.choices.hour = hour;
      if (this.choices.saleType === undefined)
      {
        this.choices.saleType = {
          id_sale_type: hour.id_sale_type_list[hour.id_sale_type_list.length - 1]
        };
      }
      if (!this.isMobileDevice())
      {
        this.next();
      }
    },
    onPeopleSelect(isGroup, people) {

      if (!isGroup)
      {
        this.peopleSelectModel = "";
      }
      this.choices.people = people;
      if (!this.isMobileDevice())
      {
        this.next();
      }
    },
    onPhoneInputFieldInput(e) {

      const el = e.target;
      const value = el.value;
      const pattern = new RegExp(el.dataset.inputValidationPattern);

      if (value.length > 0 && pattern.test(value) === false)
      {
        el.value = this.choices.phone || "";
      }
    },
    onSaleTypeSelect(saleType) {

      this.choices.saleType = saleType;
      if (!this.isMobileDevice())
      {
        this.next();
      }
    },
    onSubmit() {

      const restaurantId = this.restaurantId;
      const customerData = {
        customer_civility: this.choices.title,
        customer_email: this.choices.email,
        customer_first_name: this.choices.firstName,
        customer_last_name: this.choices.lastName,
        customer_mobile_phone: `${this.choices.phonePrefix}-${this.choices.phone}`,
        customer_is_newsletter: this.choices.optin
      };
      forkBooking.createCustomer(restaurantId, customerData).done(response => {

        if (response.result !== 1)
        {
          console.error("LaFourchette API error", response);
          return;
        }

        const datetime = this.choices.hour.datetime;
        const peopleCount = this.choices.people.nb_people;
        const saleTypeId = this.choices.saleType !== undefined ? this.choices.saleType.id_sale_type : null;
        const customerId = response.data.customer_id_customer;

        forkBooking.createBooking(restaurantId, datetime, peopleCount, customerId, saleTypeId).done(response => {

          if (response.result !== 1)
          {
            console.error("LaFourchette API error", response);
            this.apiErrorMessage = response.result_code;
            return;
          }
          this.reservationData = response.data;
          this.next();
        });
      });
      digitalData.clic = {
        name: this.analyticsName,
        type: this.analyticsType,
        url: window.location.href
      };
      _satellite.track(this.analyticsCall);
    },
    startLoading() {

      this.isLoading = true;
    },
    stopLoading() {

      this.isLoading = false;
    }
  },
  mounted() {

    const dataSet = this.$el.dataset;

    this.analyticsCall = dataSet.analyticsCall;
    this.analyticsName = dataSet.analyticsName;
    this.analyticsType = dataSet.analyticsType;
    this.menuOfferLabel = dataSet.menuOfferLabel;
    this.restaurantId = dataSet.restaurantId;
    this.goToStep(0);
    console.log("lafourchette booking component mounted");
  }
});
