<template>

   <!-- step0 -->
   <show-pane v-if="flag.showPane"
      v-bind:context="this.context"
      v-bind:options="this.options"
      v-bind:defaultz="this.defaultz"
      v-bind:entity="this.entity"
      v-bind:flag="this.flag"
      v-bind:useDatePane="this.useDatePane"
      @openEditPane="openEditPane"
      ref="showAddress">
   </show-pane>

   <!-- step 1 -->
   <teleport to="body" v-if="inModal">
      <modal v-if="flag.suggestPane"
         modalDialogClass="modal-dialog-scrollable modal-xl"
         @close="resetPane">

         <template v-slot:header>
            <h2 class="modal-title">{{ $t(getTextTitle) }}
               <span v-if="flag.loading" class="loading">
                  <i class="fa fa-circle-o-notch fa-spin fa-fw"></i>
                  <span class="sr-only">{{ $t('loading') }}</span>
               </span>
            </h2>
         </template>

         <template v-slot:body>
            <suggest-pane
               v-bind:context="this.context"
               v-bind:options="this.options"
               v-bind:defaultz="this.defaultz"
               v-bind:entity="this.entity"
               v-bind:flag="this.flag"
               @pick-address="this.pickAddress"
               ref="suggestAddress">
            </suggest-pane>
         </template>

         <template v-slot:footer>
            <button @click="openEditPane"
               class="btn btn-create">
               {{ $t('create_a_new_address')}}
            </button>
         </template>

      </modal>
   </teleport>
   <div class="mt-4" v-else>
      <suggest-pane v-if="flag.suggestPane"
         v-bind:context="this.context"
         v-bind:options="this.options"
         v-bind:defaultz="this.defaultz"
         v-bind:entity="this.entity"
         v-bind:flag="this.flag"
         v-bind:insideModal="false"
         @pick-address="this.pickAddress"
         ref="suggestAddress">

         <template v-slot:before v-if="!bypassFirstStep">
            <a class="btn btn-cancel" @click="resetPane">
               {{ $t('action.cancel') }}
            </a>
         </template>
         <template v-slot:action>
            <li>
               <button @click="openEditPane"
                  class="btn btn-create">
                  {{ $t('create_a_new_address')}}
               </button>
            </li>
         </template>

      </suggest-pane>
   </div>

   <!-- step 2 -->
   <teleport to="body" v-if="inModal">
      <modal v-if="flag.editPane"
         modalDialogClass="modal-dialog-scrollable modal-xl"
         @close="resetPane">

         <template v-slot:header>
            <h2 class="modal-title">{{ $t(getTextTitle) }}
               <span v-if="flag.loading" class="loading">
                  <i class="fa fa-circle-o-notch fa-spin fa-fw"></i>
                  <span class="sr-only">{{ $t('loading') }}</span>
               </span>
            </h2>
         </template>

         <template v-slot:body>
            <edit-pane
               v-bind:context="this.context"
               v-bind:options="this.options"
               v-bind:defaultz="this.defaultz"
               v-bind:entity="this.entity"
               v-bind:flag="this.flag"
               v-bind:errors="this.errors"
               v-bind:checkErrors="this.checkErrors"
               @getCities="getCities"
               @getReferenceAddresses="getReferenceAddresses">
            </edit-pane>
         </template>

         <template v-slot:footer>
            <!--<button class="btn btn-cancel change-icon" @click="resetPane">{{ $t('action.cancel') }}</button>-->
            <button v-if="!this.context.edit && this.useDatePane" class="btn btn-update change-icon" @click="closeEditPane">
               {{ $t('nav.next')}}
               <i class="fa fa-fw fa-arrow-right"></i>
            </button>
            <button v-else class="btn btn-save" @click="closeEditPane">
               {{ $t('action.save')}}
            </button>
         </template>

      </modal>
   </teleport>
   <div class="mt-4" v-else>
      <edit-pane v-if="flag.editPane"
         v-bind:context="this.context"
         v-bind:options="this.options"
         v-bind:defaultz="this.defaultz"
         v-bind:entity="this.entity"
         v-bind:flag="this.flag"
         v-bind:errors="this.errors"
         v-bind:checkErrors="this.checkErrors"
         v-bind:insideModal="false"
         @getCities="getCities"
         @getReferenceAddresses="getReferenceAddresses">

         <template v-slot:before>
            <a class="btn btn-cancel" @click="resetPane">
               {{ $t('action.cancel') }}
            </a>
         </template>
         <template v-slot:action>
            <li v-if="!this.context.edit && this.useDatePane">
               <button class="btn btn-update change-icon" @click="closeEditPane">
                  {{ $t('nav.next')}}
                  <i class="fa fa-fw fa-arrow-right"></i>
               </button>
            </li>
            <li v-else>
               <button class="btn btn-save" @click="closeEditPane">
                  {{ $t('action.save')}}
               </button>
            </li>
         </template>

      </edit-pane>
   </div>

   <!-- step 3 -->
   <teleport to="body" v-if="inModal">
      <modal v-if="flag.datePane"
             modalDialogClass="modal-dialog-scrollable modal-xl"
             @close="resetPane">

         <template v-slot:header>
            <h2 class="modal-title">{{ $t(getTextTitle) }}
               <span v-if="flag.loading" class="loading">
                  <i class="fa fa-circle-o-notch fa-spin fa-fw"></i>
                  <span class="sr-only">{{ $t('loading') }}</span>
               </span>
            </h2>
         </template>

         <template v-slot:body>
            <date-pane
               v-bind:context="this.context"
               v-bind:options="this.options"
               v-bind:defaultz="this.defaultz"
               v-bind:entity="this.entity"
               v-bind:flag="this.flag"
               ref="dateAddress">
            </date-pane>
         </template>

         <template v-slot:footer>
            <button class="btn btn-misc" @click="openEditPane">
               <i class="fa fa-fw fa-arrow-left"></i>
               {{ $t('nav.previous')}}
            </button>
            <button class="btn btn-save" @click="closeDatePane">
               {{ $t('action.save')}}
            </button>
            <!-- -->
         </template>

      </modal>
   </teleport>
   <div class="mt-4" v-else>
      <date-pane v-if="flag.datePane"
         v-bind:context="this.context"
         v-bind:options="this.options"
         v-bind:defaultz="this.defaultz"
         v-bind:entity="this.entity"
         v-bind:flag="this.flag"
         v-bind:insideModal="false"
         ref="dateAddress">

         <template v-slot:before>
            <button class="btn btn-misc" @click="openEditPane">
               <i class="fa fa-fw fa-arrow-left"></i>
               {{ $t('nav.previous')}}
            </button>
         </template>
         <template v-slot:action>
            <li>
               <button class="btn btn-save" @click="closeDatePane">
                  {{ $t('action.save')}}
               </button>
            </li>
         </template>

      </date-pane>
   </div>

</template>

<script>
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import {
  duplicateAddress,
  fetchCountries,
  fetchCities,
  fetchReferenceAddresses,
  getAddress,
  patchAddress,
  postAddress,
  postPostalCode,
} from '../api';
import { postAddressToPerson, postAddressToHousehold } from "ChillPersonAssets/vuejs/_api/AddAddress.js";
import ShowPane from './ShowPane.vue';
import SuggestPane from './SuggestPane.vue';
import EditPane from './EditPane.vue';
import DatePane from './DatePane.vue';

export default {
   name: "AddAddress",
   props: ['context', 'options', 'addressChangedCallback'],
   components: {
      Modal,
      ShowPane,
      SuggestPane,
      EditPane,
      DatePane
   },
   emits: {
     pickAddress: null
   },
   data() {
      return {
         flag: {
            showPane: true, // begin with showPane
            suggestPane: false,
            editPane: false,
            datePane: false,
            loading: false,
            success: false,
            dirty: false
         },
         errors: [],
         defaultz: {
            button: {
               text: { create: 'add_an_address_title', edit: 'edit_address' },
               type: { create: 'btn-create', edit: 'btn-update'},
               displayText: true
            },
            title: { create: 'add_an_address_title', edit: 'edit_address' },
            openPanesInModal: true,
            stickyActions: false,
             // show a message when no address.
             // if set to undefined, the value will be equivalent to false if stickyActions is false, true otherwise.
            showMessageWhenNoAddress: undefined,
            useDate: {
               validFrom: false,
               validTo: false
            },
            onlyButton: false
         },
         entity: {
            address: {}, // <== loaded and returned
            loaded: {
               countries: [],
               cities: [],
               addresses: [],
            },
            selected: {  // <== make temporary changes
               isNoAddress: false,
               country: {},
               city: {},
               postcode: {
                  code: null,
                  name: null
               },
               address: {},
               writeNew: {
                  address: false,
                  postcode: false
               },
               valid: {
                  from: new Date(),
                  to:  null
               }
            },
            addressMap: {
               // Note: LeafletJs demands [lat, lon]
               // cfr https://macwright.com/lonlat/
               center : [48.8589, 2.3469],
               zoom: 12
            },
         },
         errorMsg: []
      }
   },
   computed: {
      inModal() {
         return (typeof this.options.openPanesInModal !== 'undefined') ?
            this.options.openPanesInModal : this.defaultz.openPanesInModal;
      },
      validFrom() {
         return (typeof this.options.useDate !== 'undefined' && typeof this.options.useDate.validFrom !== 'undefined') ?
            this.options.useDate.validFrom : this.defaultz.useDate.validFrom;
      },
      validTo() {
         return (typeof this.options.useDate !== 'undefined' && typeof this.options.useDate.validTo !== 'undefined') ?
            this.options.useDate.validTo : this.defaultz.useDate.validTo ;
      },
      useDatePane() {
         return (this.validFrom || this.validTo) ? true : false;
      },
      hasSuggestions() {
         if (typeof(this.context.suggestions) !== 'undefined') {
            console.log('hasSuggestions', this.context.suggestions);
            return this.context.suggestions.length > 0;
         }
         return false;
      },
      displaySuggestions() {
         return !this.context.edit && this.hasSuggestions;
      },
      getTextTitle() {
         if ( typeof this.options.title !== 'undefined'
            && ( this.options.title.edit !== null
               || this.options.title.create !== null
            )) {
            return (this.context.edit) ? this.options.title.edit : this.options.title.create;
         }
         return (this.context.edit) ? this.defaultz.title.edit : this.defaultz.title.create;
      },
      bypassFirstStep() {
         // exception: passing step0 if new address and pane are not in modal
         return !this.context.edit && !this.inModal;
      },
      forceRedirect() {
         return (!(this.context.backUrl === null || typeof this.context.backUrl === 'undefined'));
      }
   },
   mounted() {

      //console.log('validFrom', this.validFrom);
      //console.log('validTo', this.validTo);
      //console.log('useDatePane', this.useDatePane);

      console.log('Mounted now !');
      if (this.context.edit) {
         console.log('getInitialAddress', this.context.addressId);
         this.getInitialAddress(this.context.addressId);
      }
      this.openShowPane();

   },
   methods: {

      /*
      *  Opening and closing Panes when interacting with buttons
      */
      openShowPane() {
         if (this.flag.editPane === false && this.bypassFirstStep) {
            console.log('bypassFirstStep');
            this.closeShowPane();
            this.openEditPane();
         } else {
            this.flag.showPane = true;
            console.log('step0: open the Show Panel');
         }
      },
      closeShowPane() {
         // Show pane can be closed only when openPanesInModal is false
         if (!this.inModal) {
            this.flag.showPane = false;
            console.log('step0: close the Show Panel');
         }
      },
      openSuggestPane() {
         this.flag.suggestPane = true;
         console.log('step1: open the Suggestion Panel');
      },
      closeSuggestPane() {
         this.flag.suggestPane = false;
         console.log('step1: close the Suggestion Panel');
      },
      openEditPane() {
         if (this.flag.suggestPane === false && this.displaySuggestions) {
            console.log('displaySuggestions');
            this.openSuggestPane();
         } else {
            if (this.flag.datePane === false) {
               this.initForm(); // reset form except if we come back from datePane
            }
            this.getCountries(); // will open editPane when resolve promise
         }
      },
      closeEditPane() {
         this.flag.editPane = false;
         console.log('step2: close the Edit Panel');
         if (!this.context.edit && this.useDatePane) {
            this.openDatePane();
         } else {
            this.applyChanges();
            if (!this.forceRedirect) {
               this.openShowPane();
            }
         }
      },
      openDatePane() {
         this.flag.datePane = true;
         console.log('step3: open the Date Panel');
      },
      closeDatePane() {
         this.applyChanges();
         this.flag.datePane = false;
         console.log('step3: close the Date Panel');
      },
      resetPane() {
         console.log('resetPane');
         this.flag.suggestPane = false;
         this.flag.editPane = false;
         this.flag.datePane = false;
         this.openShowPane();
      },

      /*
      *  What happens when submitting last Pane:
      *  - redirect or reset pane,
      *  - change context to editing
      */
      afterLastPaneAction(params) {
         this.initForm();
         if (this.forceRedirect) {
            console.log("redirect to backUrl");
            window.location.assign(this.context.backUrl);
         } else {
            console.log("don't redirect");
            this.resetPane();
            if (!this.context.edit) {
               this.context.edit = true;
               this.context.addressId = params.addressId;
               console.log("context is now edit, with address", params.addressId);
            }
         }
      },

      /*
      *  Async Fetch datas
      */
      getInitialAddress(id) {
         this.flag.loading = true;
         getAddress(id).then(
            address => new Promise((resolve, reject) => {
               this.entity.address = address;
               this.flag.loading = false;
               resolve();
         }))
         .catch((error) => {
            this.errorMsg.push(error.message);
            this.flag.loading = false;
         });
      },

      getCountries() {
         this.flag.loading = true;
         fetchCountries().then(
            countries => new Promise((resolve, reject) => {
               this.entity.loaded.countries = countries.results;
               if (this.flag.showPane === true) {
                  this.closeShowPane();
               }
               if (this.flag.suggestPane === true) {
                  this.closeSuggestPane();
               }
               if (this.flag.datePane === true) {
                  this.flag.datePane = false;
               }
               console.log('step2: open the Edit panel');
               this.flag.editPane = true;
               this.flag.loading = false;
               resolve()
         }))
         .catch((error) => {
            this.errorMsg.push(error.message);
            this.flag.loading = false;
         });
      },

      getCities(country) {
         this.flag.loading = true;
         fetchCities(country).then(
            cities => new Promise((resolve, reject) => {
               this.entity.loaded.cities = cities.results.filter(c => c.origin !== 3); // filter out user-defined cities
               this.flag.loading = false;
               resolve();
         }))
         .catch((error) => {
            this.errorMsg.push(error.message);
            this.flag.loading = false;
         });
      },

      getReferenceAddresses(city) {
         this.flag.loading = true;
         fetchReferenceAddresses(city).then(
            addresses => new Promise((resolve, reject) => {
               this.entity.loaded.addresses = addresses.results;
               this.flag.loading = false;
               resolve();
         }))
         .catch((error) => {
            this.errorMsg.push(error.message);
            this.flag.loading = false;
         });
      },

      checkErrors() {
         this.errors = [];
         if (this.entity.selected.country === null) {
            this.errors.push("Un pays doit être sélectionné.");
         }
         if (this.entity.selected.city === null) {
            this.errors.push("Une ville doit être sélectionnée.");
         }
      },

      /*
      *   Make form ready for new changes
      */
      initForm() {
         console.log('init form');

         this.entity.loaded.addresses = [];
         this.entity.loaded.cities = [];
         this.entity.loaded.countries = [];

         this.entity.selected.isNoAddress = (this.context.edit && this.entity.address.text === '') ? true : false;

         this.entity.selected.country = this.context.edit ? this.entity.address.country : {};
         this.entity.selected.postcode = this.context.edit ? this.entity.address.postcode : {};
         this.entity.selected.city = {};

         this.entity.selected.address = {};
         this.entity.selected.address.street = this.context.edit ? this.entity.address.street: null;
         this.entity.selected.address.streetNumber = this.context.edit ? this.entity.address.streetNumber: null;
         this.entity.selected.address.floor = this.context.edit ? this.entity.address.floor: null;
         this.entity.selected.address.corridor = this.context.edit ? this.entity.address.corridor: null;
         this.entity.selected.address.steps = this.context.edit ? this.entity.address.steps: null;
         this.entity.selected.address.flat = this.context.edit ? this.entity.address.flat: null;
         this.entity.selected.address.buildingName = this.context.edit ? this.entity.address.buildingName: null;
         this.entity.selected.address.distribution = this.context.edit ? this.entity.address.distribution: null;
         this.entity.selected.address.extra = this.context.edit ? this.entity.address.extra: null;

         this.entity.selected.writeNew.address = this.context.edit && this.entity.address.addressReference === null && this.entity.address.street.length > 0
         this.entity.selected.writeNew.postcode = false // NB: this used to be this.context.edit, but think it was erroneous;
         console.log('!! just set writeNew.postcode to', this.entity.selected.writeNew.postcode);
      },

      /*
      *  When changes are validated (get out step2 edit pane, button valid),
      *  apply some transformations before asyncing with backend
      *  from entity.selected to entity.address
      */
      applyChanges()
      {
         console.log('apply changes');
         let newAddress = {
            'isNoAddress': this.entity.selected.isNoAddress,
            'street': this.entity.selected.isNoAddress ? '' : this.entity.selected.address.street,
            'streetNumber': this.entity.selected.isNoAddress ? '' : this.entity.selected.address.streetNumber,
            'postcode': {'id': this.entity.selected.city.id },
            'floor': this.entity.selected.address.floor,
            'corridor': this.entity.selected.address.corridor,
            'steps': this.entity.selected.address.steps,
            'flat': this.entity.selected.address.flat,
            'buildingName': this.entity.selected.address.buildingName,
            'distribution': this.entity.selected.address.distribution,
            'extra': this.entity.selected.address.extra
         };

         if (this.entity.selected.address.point !== undefined) {
            newAddress = Object.assign(newAddress, {
               'point': this.entity.selected.address.point.coordinates
            });
         } else {
            if (this.entity.selected.postcode.coordinates) {
               newAddress = Object.assign(newAddress, {
                  'point': this.entity.selected.postcode.coordinates
               });
            }
         }

         // add the address reference, if any
         if (this.entity.selected.address.addressReference !== undefined) {
             newAddress = Object.assign(newAddress, {
                 'addressReference': this.entity.selected.address.addressReference
             });
         }

         if (this.validFrom) {
            console.log('add validFrom in fetch body', this.entity.selected.valid.from);
            newAddress = Object.assign(newAddress, {
               'validFrom': {
                  datetime: `${this.entity.selected.valid.from.toISOString().split('T')[0]}T00:00:00+0100`
               }
            });
         }
         if (this.validTo && null !== this.entity.selected.valid.to) {
            console.log('add validTo in fetch body', this.entity.selected.valid.to);
            newAddress = Object.assign(newAddress, {
               'validTo': {
                  datetime: `${this.entity.selected.valid.to.toISOString().split('T')[0]}T00:00:00+0100`
               }
            });
         }
         if (this.entity.selected.writeNew.postcode) {
            let newPostcode = this.entity.selected.postcode;
            newPostcode = Object.assign(newPostcode, {
               'country': {'id': this.entity.selected.country.id },
            });//TODO why not assign postcodeBody here = Object.assign(postcodeBody, {'origin': 3}); ?
            console.log('writeNew postcode is true! newPostcode: ', newPostcode);
            newAddress = Object.assign(newAddress, {
               'newPostcode': newPostcode
            });
         }

         if (!this.context.edit) {
            this.addNewAddress(newAddress)
               .then(payload => this.addressChangedCallback(payload));
         } else {
            this.updateAddress({
               addressId: this.context.addressId,
               newAddress: newAddress
            })
            .then(payload => this.addressChangedCallback(payload));
         }
      },

      /*
      *  Async POST transactions,
      *  creating new address, and receive backend datas when promise is resolved
      */
      addNewAddress(payload)
      {
         console.log('addNewAddress', payload);
         this.flag.loading = true;

         if ('newPostcode' in payload) {

            let postcodeBody = payload.newPostcode;
            postcodeBody = Object.assign(postcodeBody, {'origin': 3});
            console.log('juste before post new postcode', postcodeBody);
            return postPostalCode(postcodeBody)
               .then(postalCode =>  {
                  console.log('new postcode created', postalCode.id);
                  payload.postcode = {'id': postalCode.id };
                  return this.postNewAddress(payload);
               });

         } else {
            return this.postNewAddress(payload);
         }
      },

      postNewAddress(payload)
      {
         console.log('postNewAddress', payload);
         return postAddress(payload)
            .then(address => new Promise((resolve, reject) => {
               this.entity.address = address;
               this.flag.loading = false;
               this.flag.success = true;
               resolve({
                 address,
                 targetOrigin: this.context.target,
                 // for "legacy" use:
                  target: this.context.target.name,
                  targetId: this.context.target.id,
                  addressId: this.entity.address.address_id,
                  }
               );
            }))
            .catch((error) => {
               this.errorMsg.push(error);
               this.flag.loading = false;
            });
      },

      /*
      *  Async PATCH transactions,
      *  then update existing address with backend datas when promise is resolved
      */
      updateAddress(payload) {
         this.flag.loading = true;

         // TODO change the condition because it writes new postal code in edit mode now: !writeNewPostalCode
         // BUG réécrit un postcode à chaque édition !
         if ('newPostcode' in payload.newAddress) {

            let postcodeBody = payload.newAddress.newPostcode;
            postcodeBody = Object.assign(postcodeBody, {'origin': 3});

            console.log('juste before post new postcode', postcodeBody);
            return postPostalCode(postcodeBody)
               .then(postalCode => {
                  console.log('new postcode created', postalCode.id);
                  payload.newAddress.postcode = {'id': postalCode.id };
                  return this.patchExistingAddress(payload);
               });

         } else {
            return this.patchExistingAddress(payload);
         }
      },

      patchExistingAddress(payload) {
         console.log('patchExistingAddress', payload);
         return patchAddress(payload.addressId, payload.newAddress)
            .then(address => new Promise((resolve, reject) => {
                  this.entity.address = address;
                  this.flag.loading = false;
                  this.flag.success = true;
                  return resolve({
                    address,
                    targetOrigin: this.context.target,
                    // for "legacy" use:
                     target: this.context.target.name,
                     targetId: this.context.target.id,
                     addressId: this.entity.address.address_id
                  });
               })
            )
            .catch((error) => {
               this.errorMsg.push(error);
               this.flag.loading = false;
            });
      },

     /**
      *
      * Called when the event pick-address is emitted, which is, by the way,
      * called when an address suggestion is picked.
      *
      * @param address the address selected
      */
      pickAddress(address) {
         console.log('pickAddress', address);
         duplicateAddress(address).then(newAddress => {
           this.entity.address = newAddress;
           this.flag.loading = false;
           this.flag.success = true;
           let payload = {
             address: newAddress,
             targetOrigin: this.context.target,
             // for "legacy" use:
             target: this.context.target.name,
             targetId: this.context.target.id,
             addressId: this.entity.address.address_id
           };
           this.addressChangedCallback(payload);
           this.closeSuggestPane();
         });
      }
   }
}
</script>

<style lang="scss">
div.entity-address {
   position: relative;
   div.loading {
      position: absolute;
      right: 0; top: -55px;
   }
}
h4.h3 {
   font-weight: bold;
}
</style>
