import '@things-factory/biz-ui'
import '@things-factory/grist-ui'
import '@things-factory/import-ui'
import '@things-factory/component-ui'
import '../../../components/select-inventory-popup'
import '../../../components/select-product-popup'

import gql from 'graphql-tag'
import { css, html } from 'lit-element'

import { getCodeByName } from '@things-factory/code-base'
import { MultiColumnFormStyles, SingleColumnFormStyles } from '@things-factory/form-ui'
import { i18next, localize } from '@things-factory/i18n-base'
import { openPopup } from '@things-factory/layout-base'
import { client, CustomAlert, navigate, PageView } from '@things-factory/shell'
import { CommonButtonStyles } from '@things-factory/styles'
import { isMobileDevice } from '@things-factory/utils'

import { fetchSettingRule } from '../../../../fetch-setting-value'
import { GROUP_TYPES, ORDER_INVENTORY_STATUS, ORDER_TYPES, PICKING_STANDARD, RO_TYPES } from '../../../constants'

class CreateB2CReleaseOrder extends localize(i18next)(PageView) {
  static get properties() {
    return {
      /* RO Form Fields */
      _isLmd: Boolean,
      _isCod: Boolean,
      _isLmdExists: Boolean,
      _ownTransport: Boolean,
      _warehouseTransport: Boolean,
      _crossDocking: Boolean,
      _exportOption: Boolean,
      refNo: String,
      refNo2: String,
      refNo3: String,
      releaseDate: Date,
      _paidAmount: Number,
      collectionOrderNo: String,
      _bizplaces: Object,
      _bizplaceId: String,
      _bizplaceName: String,
      /* RO Form Fields */

      _files: Array,

      _bundleSettingData: Array,
      _pickingStd: String,
      _productBundleName: String,
      _selectedInventories: Array,
      inventoryGristConfig: Object,
      inventoryData: Object,
      bundleData: Object,
      crossDockingProducts: Array,
      _releaseByBundleQty: Number,
      _releaseByBundleUomValue: Number,
      _releaseOrderNo: String,
      _ganNo: String,
      _checkTransport: Boolean,
      _packingOption: Boolean,
      _enableTransportationServiceSetting: Boolean,
      _selectedCP: String,

      /* Shipping Form Field */
      _contactPointId: String,
      _contactPointName: String,
      _companyName: String,
      _attentionTo: String,
      _deliveryPostCode: Array,
      _deliveryState: String,
      _deliveryCity: String,
      _deliveryContact: String,
      _deliveryFullAddress: String,
      _selectedPostCode: String,
      _selectedDeliveryCountry: String,
      _selectedBillingCountry: String,
      _billingCountry: String,
      _billingPostCode: Array,
      _billingState: String,
      _billingCity: String,
      _billingContact: String,
      _billingFullAddress: String,
      _selectedBillingPostCode: String,
      _switchDeliveryCountryInput: Boolean,
      _switchBillingCountryInput: Boolean,
      _allCountry: Array,
      _containerClosureDate: Date,
      _recallToggle: Boolean,
      _savedStrategy: String,

      // refractor
      _contactPointInfo: Object,

      /* Tab Toggle*/
      _showReleasedOrderInfo: Boolean,
      _showShippingInfo: Boolean,
      _disableBillingAddress: Boolean,
      _showExportInfo: Boolean,

      // Type
      _selectBy: String
    }
  }

  static get styles() {
    return [
      MultiColumnFormStyles,
      SingleColumnFormStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow-x: auto;
        }
        .container {
          flex: 1;
          display: flex;
          overflow-y: auto;
        }
        .picking-std-container {
          margin-top: 0px;
        }
        [options-wrap] * {
          vertical-align: middle;
        }
        [options-wrap] input[type='checkbox'] {
          left: 0;
        }
        [options-wrap] input[type='checkbox'] + label {
          margin-right: 20px;
          padding-left: 0;
        }
        [title] {
          margin-top: -5px;
          margin-bottom: -5px;
        }
        [attachment-wrap] {
          display: flex;
          flex-direction: row;
          justify-content: center;
          grid-column: span 24;
        }
        [attachment-wrap] label {
          width: 8%;
        }
        [attachment-wrap] file-uploader {
          flex: 1;
          margin: 0 var(--margin-wide) 0 var(--margin-narrow);
        }
        .grist {
          background-color: var(--main-section-background-color);
          display: flex;
          flex-direction: column;
          flex: 1;
          overflow-y: auto;
        }
        data-grist {
          overflow-y: hidden;
          flex: 1;
        }
        h2 {
          padding: var(--subtitle-padding);
          font: var(--subtitle-font);
          color: var(--subtitle-text-color);
          border-bottom: var(--subtitle-border-bottom);
        }
        .grist h2 {
          margin: var(--grist-title-margin);
          border: var(--grist-title-border);
          font: var(--grist-title-font);
          color: var(--secondary-color);
        }

        .grist h2 mwc-icon {
          vertical-align: middle;
          margin: var(--grist-title-icon-margin);
          font-size: var(--grist-title-icon-size);
          color: var(--grist-title-icon-color);
        }

        h2 + data-grist {
          padding-top: var(--grist-title-with-grid-padding);
        }

        .summary {
          background-color: var(--main-section-background-color);
          display: flex;
          flex-direction: column;
          overflow-y: auto;
          align-items: flex-end;
          padding: var(--data-list-item-padding);
          display: grid;
          font-size: 14px;
          color: #394e64;
          grid-template-columns: repeat(2, 1fr);
          grid-auto-rows: minmax(24px, auto);
        }

        .label-remindContainerDeparture {
          margin-left: 20px;
          width: 50%;
        }

        [hidden] {
          display: none;
        }
        @media screen and (max-width: 460px) {
          [attachment-wrap] {
            grid-column: span 12;
          }
        }
        @media screen and (min-width: 1201px) and (max-width: 2000px) {
          [attachment-wrap] {
            grid-column: span 36;
          }
        }
        @media screen and (min-width: 2001px) {
          [attachment-wrap] {
            grid-column: span 48;
          }
          [attachment-wrap] label {
            width: 6%;
          }
        }

        .section-header {
          grid-column: span 36 / auto !important;
          text-align: left !important;
          margin-top: 10px !important;
          font-weight: 600 !important;
        }
        .quick-find-content-container {
          margin: 0 15px;
        }

        @media screen and (max-width: 480px) {
          .section-header {
            grid-column: span 12 / auto !important;
          }
          .quick-find-content-container {
            margin: 0;
          }
        }

        .header-with-checkbox {
          display: flex;
          align-self: flex-end;
          align-items: center;
          grid-column: span 36 / auto !important;
          text-align: left !important;
          margin-top: 10px !important;
          font-weight: 600 !important;
          margin-right: 2px; /* Spacing between header and checkbox */
        }

        .checkbox-container label {
          margin-left: 1px;
        }

        .checkbox-wrapper {
          margin-top: 10px;
        }

        .checkbox-wrapper::before {
          content: '('; /* Left bracket */
          margin-left: 2em;
          font-size: 0.9em; /* Adjust size as needed */
          font-weight: 100 !important;
        }

        .checkbox-wrapper::after {
          content: ')'; /* Right bracket */
          margin-left: 1em; /* Space between bracket and checkbox */
          font-size: 0.9em; /* Adjust size as needed */
          font-weight: 100 !important;
        }

        .checkbox-wrapper input[type='checkbox'] {
          width: 10px;
          height: 10px;
        }

        #matchDeliveryAddress {
          margin-top: 5px !important;
        }
      `
    ]
  }

  get context() {
    return {
      title: i18next.t('title.create_release_order'),
      actions: [
        {
          title: i18next.t('button.submit'),
          action: this._generateReleaseOrder.bind(this),
          ...CommonButtonStyles.submit
        }
      ],
      exportable: {
        name: i18next.t('title.create_release_order'),
        data: this._exportableData.bind(this)
      },
      importable: {
        handler: this._importableData.bind(this)
      }
    }
  }

  render() {
    const RELEASE_ORDER_TABS = {
      RELEASE_ORDER_INFO: i18next.t('label.order'),
      SHIPPING_INFO: i18next.t('label.shipment')
    }

    const orderSet = {
      [RELEASE_ORDER_TABS.RELEASE_ORDER_INFO]: {},
      [RELEASE_ORDER_TABS.SHIPPING_INFO]: {}
    }

    return html`
      <div class="quick-find-content-container" >
        <quick-find-content
        id="order-items-list"
        name="quickFindContent"
        .data="${orderSet}"
        @tabChanged="${e => {
          this._tabChange(e.detail.currentTabKey)
        }}"
        ></quick-find-content>
      </div>
    
      <form name="releaseOrder" class="multi-column-form" autocomplete="off" ?hidden="${this._showReleasedOrderInfo}">
        <fieldset>
          <legend>${i18next.t('title.release_order')}</legend>

          <label>${i18next.t('label.options')}</label>
          <div options-wrap>
            <input
              id="lmd"
              type="checkbox"
              name="lmd"
              ?checked="${this._isLmd}"
              ?disabled="${!this._isLmdExists}"
              @change="${e => {
                this._isLmd = e.currentTarget.checked
              }}"
            />
            <label for="lmd">${i18next.t('label.lmd')}</label>
            
            <input
              id="codOption"
              type="checkbox"
              name="codOption"
              ?checked="${this._isCod}"
              @change="${e => {
                this._isCod = e.currentTarget.checked
              }}"
              />
              <label for="cod">${i18next.t('label.cod')}</label>
          </div>

          <label>${i18next.t('label.company')}</label>
          <input type="hidden" name="bizplaceId" value="${this._bizplaceId}" />
          <input
            type="text"
            name="bizplaceName"
            value="${this._bizplaceName}"
            @click="${this._openBizplacesSelector.bind(this)}"
          />

          <label>${i18next.t('label.ref_no')}</label>
          <input name="refNo" .value="${this.refNo}"/>

          <label>${i18next.t('label.ref_no_2')}</label>
          <input name="refNo2" .value="${this.refNo2}" />

          <label>${i18next.t('label.ref_no_3')}</label>
          <input name="refNo3" .value="${this.refNo3}" />

          <label>${i18next.t('label.release_date')}</label>
          <input
            name="releaseDate"
            type="date"
            min="${this._getStdDate()}"
            .value="${this.releaseDate}"
            required
            ?disabled="${this._crossDocking}"
           
            @change="${this._validateDate}"
          />

          <label ?hidden="${!this._isCod}">${i18next.t('label.paid_amount')}</label>
          <input 
            name="paidAmount" 
            type="number"
            ?hidden="${!this._isCod}"
            min="0"
          />
          
          ${
            this._crossDocking
              ? html`
                  <label for="ganNo">${i18next.t('label.arrival_notice')}</label>
                  <input readonly name="ganNo" value="${this._ganNo}" />
                `
              : ''
          }

          <div attachment-wrap>
            <label>${i18next.t('label.invoice')}</label>
            <file-uploader
              class="align-file-uploader"
              name="attachments"
              id="uploadInvoice"
              label="${i18next.t('label.select_file')}"
              accept="*"
              multiple="true"
             
              custom-input
            ></file-uploader>
          </div>
            
          <div attachment-wrap>
            <label ?hidden="${this._isLmd}">${i18next.t('label.awb')}</label>
            <file-uploader
            class="align-file-uploader"
              name="attachments"
              id="uploadAwb"
              label="${i18next.t('label.select_file')}"
              accept="*"
              multiple="true"
              ?hidden="${this._isLmd}"
             
              custom-input
            ></file-uploader>
          </div>
        </fieldset>
      </form>


      <form name="shippingInfo" ?hidden="${this._showShippingInfo}" class="multi-column-form" autocomplete="off">
          <legend>${i18next.t('title.shipping_information')}</legend>
          
          <label>${i18next.t('label.attention_to')}</label>
          <input name="attentionTo" required .value="${this._attentionTo}" />

          <label>${i18next.t('label.contact')}</label>
          <input name="phone1" required .value="${this._deliveryContact}" /> 

        <!-- delivery -->
          <!-- <label class="section-header">${i18next.t('label.delivery_address')}</label> -->

          <div class="header-with-checkbox">
              <label class="section-header">${i18next.t('label.delivery_address')}</label>
                <div class="checkbox-wrapper">
                    <input type="checkbox" id="matchDeliveryAddress" name="matchDeliveryAddressInput" 
                          @click=${e => {
                            e.currentTarget.checked
                              ? (this._disableBillingAddress = true)
                              : (this._disableBillingAddress = false)
                          }} />
                    <label for="matchDeliveryAddress">${i18next.t('label.use_as_billing_address')}</label>
                </div>
          </div>

          <label>${i18next.t('label.delivery_address_1')}</label>
          <textarea name="deliveryAddress1" required .value="${this._deliveryAddress1}"></textarea>

          <label>${i18next.t('label.delivery_address_2')}</label>
          <textarea name="deliveryAddress2" required .value="${this._deliveryAddress2}"></textarea>

          <label>${i18next.t('label.delivery_address_3')}</label>
          <textarea name="deliveryAddress3" required .value="${this._deliveryAddress3}"></textarea>

          <label>${i18next.t('label.delivery_address_4')}</label>
          <textarea name="deliveryAddress4" required .value="${this._deliveryAddress4}"></textarea>

          <label>${i18next.t('label.delivery_address_5')}</label>
          <textarea name="deliveryAddress5" required .value="${this._deliveryAddress5}"></textarea>
          
          <label>${i18next.t('label.country')}</label>        
          <select
            name="country"
            @change=${e => {
              this._validateCountry(e)
            }}
          >
            ${this._allCountry?.map(
              (country, key) => html`<option value=${country.description}>${country.name}</option>`
            )}
        </select>


        <label>${i18next.t('label.zip_postal_code')}</label>

        ${
          this._switchDeliveryCountryInput
            ? html` <input id="deliveryPostalCode" name="postalCode" required .value="" /> `
            : html`<select
                name="postalCode"
                @change=${e => {
                  this._getStateAndCityByPostCode(e.target.value, e.target.name)
                }}
              >
                <option value=""></option>
                ${this._deliveryPostCode?.map(
                  (country, key) =>
                    html`<option value=${country.postalCode} ?selected=${this._selectedPostCode === country.postalCode}>
                      ${country.postalCode}
                    </option>`
                )}
              </select>`
        }
        

        <label>${i18next.t('label.state')}</label>
        <input name="state" required .value="${this._deliveryState}" />

        <label>${i18next.t('label.city')}</label>
        <input name="city" required .value="${this._deliveryCity}" />

        <!-- billing -->

        <label ?hidden=${this._disableBillingAddress} class="section-header">${i18next.t(
      'label.billing_address'
    )}</label>

        <label ?hidden=${this._disableBillingAddress}>${i18next.t('label.billing_address_1')}</label>
        <textarea ?hidden=${this._disableBillingAddress} name="billingAddress" required .value="${
      this._billingAddress
    }"></textarea>

        <label ?hidden=${this._disableBillingAddress}>${i18next.t('label.billing_address_2')}</label>
        <textarea ?hidden=${this._disableBillingAddress} name="billingAddress2" required .value="${
      this._billingAddress2
    }"></textarea>

        <label ?hidden=${this._disableBillingAddress}>${i18next.t('label.billing_address_3')}</label>
        <textarea ?hidden=${this._disableBillingAddress} name="billingAddress3" required .value="${
      this._billingAddress3
    }"></textarea>

        <label ?hidden=${this._disableBillingAddress}>${i18next.t('label.billing_address_4')}</label>
        <textarea ?hidden=${this._disableBillingAddress} name="billingAddress4" required .value="${
      this._billingAddress4
    }"></textarea>

        <label ?hidden=${this._disableBillingAddress}>${i18next.t('label.billing_address_5')}</label>
        <textarea ?hidden=${this._disableBillingAddress}   name="billingAddress5" required .value="${
      this._billingAddress5
    }"></textarea>

        <label ?hidden=${this._disableBillingAddress}>${i18next.t('label.country')}</label>
        <select ?hidden=${this._disableBillingAddress}
        name="billingCountry"
        ?disabled=${this._disableBillingAddress ? true : false}
        @change=${e => {
          this._validateBillingCountry(e)
        }}
        >
        ${this._allCountry?.map((country, key) => html`<option value=${country.description}>${country.name}</option>`)}
        </select>

        <label ?hidden=${this._disableBillingAddress}>${i18next.t('label.zip_postal_code')}</label>
        ${
          this._switchBillingCountryInput
            ? html`
                <input
                  ?hidden=${this._disableBillingAddress}
                  ?disabled=${this._disableBillingAddress ? true : false}
                  name="billingPostalCode"
                  required
                  .value=""
                />
              `
            : html`<select
                ?hidden=${this._disableBillingAddress}
                ?disabled=${this._disableBillingAddress ? true : false}
                name="billingPostalCode"
                @change=${e => {
                  this._getStateAndCityByPostCode(e.target.value, e.target.name)
                }}
              >
                <option value=${this._selectedBillingPostCode ? this._selectedBillingPostCode : ''} selected>
                  ${this._selectedBillingPostCode ? this._selectedBillingPostCode : ''}
                </option>
                ${this._billingPostCode?.map(
                  (country, key) => html`<option value=${country.postalCode}>${country.postalCode}</option>`
                )}
              </select>`
        }

        <label ?hidden=${this._disableBillingAddress}>${i18next.t('label.state')}</label>
        <input ?hidden=${this._disableBillingAddress} name="billingState" required 
        .value="${this._billingState}" />

        <label ?hidden=${this._disableBillingAddress}>${i18next.t('label.city')}</label>
        <input ?hidden=${this._disableBillingAddress} ?disabled=${
      this._disableBillingAddress ? true : false
    } name="billingCity" required 
        .value="${this._billingCity}" />

        <!-- <label>${i18next.t('label.billing_address')}</label>
        <textarea ?disabled=${this._disableBillingAddress ? true : false} name="billingAddress" required 
        .value="${this._billingFullAddress}"></textarea>
            
        <input type="checkbox" id="matchDeliveryAddress" name="matchDeliveryAddressInput" @click=${e => {
          e.currentTarget.checked ? (this._disableBillingAddress = true) : (this._disableBillingAddress = false)
        }} />
        <label for="matchDeliveryAddress">${i18next.t('label.match_delivery_address')}</label> -->
      </form>

      <div class="container" ?hidden=${!this._showShippingInfo}>

        <div class="grist">

          <!-- release product list-->
          <data-grist 
            id="inventory-grist"
            .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
            .config=${this.inventoryGristConfig}
            .data=${this.inventoryData}
            @record-change="${this._onProductChangeHandler.bind(this)}"
            @field-change="${this._onInventoryFieldChanged.bind(this)}"
          ></data-grist>

          <h2 ?hidden=${!this.bundleData.records?.length}>
            <mwc-icon>list_alt</mwc-icon>${this._productBundleName || i18next.t('title.product_bundle_detail')}
          </h2>

          <data-grist
            id="bundle-grist"
            ?hidden=${!this.bundleData.records?.length}
            .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
            .config=${this.bundleGristConfig}
            .data="${this.bundleData}"
            @field-change="${this._onBundleFieldChanged.bind(this)}"
          ></data-grist>
          </div>
        </div>
      </div>
    `
  }

  get releaseOrderForm() {
    return this.shadowRoot.querySelector('form[name=releaseOrder]')
  }

  get shippingInfoForm() {
    return this.shadowRoot.querySelector('form[name=shippingInfo]')
  }

  get getDeliveryAddressInfoForm() {
    return this.shadowRoot.querySelector('form[name=deliveryAddressInfo]')
  }

  get getBillingAddressInfoForm() {
    return this.shadowRoot.querySelector('form[name=billingAddressInfo]')
  }

  get _containerClosureDateInput() {
    return this.shadowRoot.querySelector('input[name=containerClosureDate]')
  }

  get _conLeavingDateInput() {
    return this.shadowRoot.querySelector('input[name=containerClosureDate]')
  }

  get shippingOrderForm() {
    return this.shadowRoot.querySelector('form[name=shippingOrder]')
  }

  get exportInfoForm() {
    return this.shadowRoot.querySelector('form[name=exportInfo]')
  }

  get _ownTransportInput() {
    return this.shadowRoot.querySelector('input[name=ownTransport]')
  }

  get _cityInput() {
    return this.shadowRoot.querySelector('input[name=city]')
  }

  get _stateInput() {
    return this.shadowRoot.querySelector('input[name=state]')
  }

  get _recallInput() {
    return this.shadowRoot.querySelector('input[name=recall]')
  }

  get _cityBillingInput() {
    return this.shadowRoot.querySelector('input[id=billingCity]')
  }

  get _stateBillingInput() {
    return this.shadowRoot.querySelector('input[name=billingState]')
  }

  get _warehouseTransportInput() {
    return this.shadowRoot.querySelector('input[name=warehouseTransport]')
  }

  get _getBillingPostalCodeInput() {
    return this.shadowRoot.querySelector('select[name=billingPostalCode]')
  }

  get _exportOptionInput() {
    return this.shadowRoot.querySelector('input[name=exportOption]')
  }

  get inventoryGrist() {
    return this.shadowRoot.querySelector('data-grist#inventory-grist')
  }

  get bundleGrist() {
    return this.shadowRoot.querySelector('data-grist#bundle-grist')
  }

  get _invoiceDocument() {
    return this.shadowRoot.querySelector('#uploadInvoice')
  }

  get _awbDocument() {
    return this.shadowRoot.querySelector('#uploadAwb')
  }

  get bizplaceIdInput() {
    return this.shadowRoot.querySelector('input[name=bizplaceId]')
  }

  get bizplaceNameInput() {
    return this.shadowRoot.querySelector('input[name=bizplaceName]')
  }

  get selectByProductInput() {
    return this.shadowRoot.querySelector('input[id=pick-by-prod]')
  }

  get selectByPalletInput() {
    return this.shadowRoot.querySelector('input[id=pick-by-pallet]')
  }

  get matchDeliveryAddressInput() {
    return this.shadowRoot?.querySelector('input[name=matchDeliveryAddressInput]')
  }

  get deliveryCountryInput() {
    return this.shadowRoot?.querySelector('select[name=country]')
  }

  get deliveryPostalCodeSelectInput() {
    return this.shadowRoot?.querySelector('select[name=postalCode]')
  }

  get deliveryPostalCodeInput() {
    return this.shadowRoot?.querySelector('input[name=postalCode]')
  }

  get deliveryStateInput() {
    return this.shadowRoot?.querySelector('input[name=state]')
  }

  get deliveryCityInput() {
    return this.shadowRoot?.querySelector('input[name=city]')
  }

  get deliveryAddressInput() {
    return this.shadowRoot?.querySelector('textarea[name=deliveryAddress1]')
  }

  get deliveryContactInput() {
    return this.shadowRoot?.querySelector('input[name=phone1]')
  }

  get billingCountryInput() {
    return this.shadowRoot?.querySelector('select[name=billingCountry]')
  }

  get billingPostalCodeSelectInput() {
    return this.shadowRoot?.querySelector('select[name=billingPostalCode]')
  }

  get billingPostalCodeInput() {
    return this.shadowRoot?.querySelector('input[name=billingPostalCode]')
  }

  get billingStateInput() {
    return this.shadowRoot?.querySelector('input[name=billingState]')
  }

  get billingCityInput() {
    return this.shadowRoot?.querySelector('input[name=billingCity]')
  }

  get billingAddressInput() {
    return this.shadowRoot?.querySelector('textarea[name=billingAddress]')
  }

  get attentionToInput() {
    return this.shadowRoot?.querySelector('input[name=attentionTo]')
  }

  get _inventoryColumns() {
    return this.inventoryGrist.columns
  }

  get quickFindContent() {
    return this.shadowRoot?.querySelector('quick-find-content[name=quickFindContent]')
  }

  get paidAmountInput() {
    return this.shadowRoot?.querySelector('input[name=paidAmount]')
  }

  constructor() {
    super()
    this.initProperties()
    this._getAllPostCode()
    this.fetchCountry()
    this._disableBillingAddress = true
    this._pickingStd = PICKING_STANDARD.SELECT_BY_PRODUCT.value
    this._bundleSettingData = []
  }

  async updated(changeProps) {
    if (changeProps.has('_pickingStd')) {
      this.switchPickingType()

      if (this.crossDockingProducts?.length > 0) {
        this.inventoryData = {
          ...this.inventoryData,
          records: this.crossDockingProducts
        }
      }
    }

    if (changeProps.has('_files') && this._files?.length) {
      this._document.reset()
    }
  }

  pageUpdated(changes) {
    if (changes.active) {
      const matches = location.pathname.match(/(?<=create_release_order\/)(.*)/g)
      if (matches?.length) {
        this._ganNo = matches[0]
      } else {
        this._ganNo = null
      }
      this._crossDocking = Boolean(this._ganNo)
      if (this._crossDocking) {
        this._pickingStd = PICKING_STANDARD.SELECT_BY_PRODUCT.value
      } else {
        this.crossDockingProducts = []
      }
    }
  }

  _clearView() {
    this.releaseOrderForm.reset()
    this.inventoryData = { ...this.inventoryData, records: [] }

    const documents = [this._document, this._awbDocument, this._invoiceDocument]

    for (const doc of documents) {
      if (doc?._files) {
        doc.reset()
      }
    }
  }

  async pageInitialized() {
    let [enableTransportationServiceSetting, bizplaces, packingTypes] = await Promise.all([
      fetchSettingRule('enable-transportation-service'),
      this.fetchBizplaces(),
      getCodeByName('PACKING_TYPES')
    ])

    this.checkActiveLmd()

    this.quickFindContent.currentTabKey = i18next.t('label.order')
    this._disableBillingAddress = true
    this._enableTransportationServiceSetting = enableTransportationServiceSetting
    this._bizplaces = bizplaces
    this.packingTypes = packingTypes

    this.bundleGristConfig = {
      list: {
        fields: ['batchId', 'productSku', 'product', 'remainQty', 'releaseQty', 'remainUomValue', 'releaseUomValue']
      },
      pagination: { infinite: true },
      rows: {
        handlers: {
          click: (columns, data, column, record, rowIndex) => {
            if (column.name) {
              this._updateReleaseQtyUomValue(record)
            }
          }
        }
      },
      columns: [
        {
          type: 'string',
          name: 'batchId',
          header: i18next.t('field.batch_id'),
          width: 150
        },
        {
          type: 'string',
          name: 'productSku',
          header: i18next.t('field.sku'),
          width: 150
        },
        {
          type: 'string',
          name: 'product',
          header: i18next.t('field.product'),
          width: 300
        },
        {
          type: 'string',
          name: 'packingType',
          header: i18next.t('field.packing_type'),
          width: 150
        },
        {
          type: 'float',
          name: 'remainQty',
          header: i18next.t('field.available_qty'),
          width: 120
        },
        {
          type: 'float',
          name: 'releaseQty',
          header: i18next.t('field.assigned_qty'),
          width: 120
        },
        {
          type: 'float',
          name: 'remainUomValue',
          header: i18next.t('field.available_uom_value'),
          width: 150
        },
        {
          type: 'string',
          name: 'releaseUomValueWithUom',
          header: i18next.t('field.assigned_uom_value'),
          width: 150
        }
      ]
    }
  }

  initProperties() {
    this._paidAmount = ''
    this._exportOption = false
    this.refNo = ''
    this.refNo2 = ''
    this.refNo3 = ''
    this.releaseDate = ''
    this.collectionOrderNo = ''
    this._files = []
    this._allCountry = []
    this.inventoryData = { ...this.inventoryData, records: [] }
    this.bundleData = { ...this.bundleData, records: [] }
    this._showReleasedOrderInfo = false
    this._showShippingInfo = true
    this._attentionTo = ''
    this._companyName = ''
    this._deliveryState = ''
    this._deliveryCity = ''
    this._deliveryAddress1 = ''
    this._deliveryAddress2 = ''
    this._deliveryAddress3 = ''
    this._deliveryAddress4 = ''
    this._deliveryAddress5 = ''
    this._billingAddress = ''
    this._billingAddress2 = ''
    this._billingAddress3 = ''
    this._billingAddress4 = ''
    this._billingAddress5 = ''
    this._deliveryContact = ''
    this._billingState = ''
    this._billingCity = ''
    this._billingFullAddress = ''
    this._billingContact = ''
    this._switchDeliveryCountryInput = false
    this._switchBillingCountryInput = false
    this._disableBillingAddress = false
    this._showExportInfo = true
    this._selectedDeliveryCountry = 'MY'
    this._selectedBillingCountry = 'MY'
    this._containerClosureDate = ''
    this._recallToggle = false
  }

  resetPage() {
    this.bundleData = {}
    this.matchDeliveryAddressInput.checked = true
    this.quickFindContent.currentTabKey = i18next.t('label.order')

    // this.initProperties()
    this._clearGristConditions()
    this._getAllPostCode()
  }

  resetOption() {
    this._isLmd = false
    this._isCod = false
  }

  async switchPickingType() {
    this.resetPage()
    this.inventoryGristConfig = {
      pagination: { infinite: true },
      rows: {
        selectable: { multiple: true },
        classifier: (record, rowIndex) => {
          return {
            emphasized: record.isCrossDocking || record.isError
          }
        },
        handlers: {
          click: (columns, data, column, record, rowIndex) => {
            if (record.groupType === GROUP_TYPES.BUNDLE.value && record.releaseQty) {
              this.fetchInventoriesByBundle(record.product.id, record.releaseQty)
              this._productBundleName = `${record.product.name}`
            } else {
              this.bundleData = {}
              this._productBundleName = null
            }
          }
        }
      },
      list: { fields: ['inventory', 'product', 'location', 'releaseQty'] },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'gutter',
          gutterName: 'button',
          icon: 'close',
          handlers: {
            click: (columns, data, column, record, rowIndex) => {
              try {
                if (record.isCrossDocking) throw new Error(i18next.t('text.cannot_delete_cross_docking_products'))
                const newData = data.records.filter((_, idx) => idx !== rowIndex)
                this.inventoryData = { ...this.inventoryData, records: newData }

                this.inventoryGrist.dirtyData.records = newData
                this._updateInventoryGristConfig()
              } catch (e) {
                this._showToast(e)
              }
            }
          }
        },
        {
          type: 'string',
          name: 'productSKU',
          header: i18next.t('field.sku'),
          width: 100
        },
        {
          type: 'object',
          name: 'product',
          header: i18next.t('field.product'),
          handlers: {
            click: (columns, data, column, record, rowIndex) => {
              this._selectBy = 'product'
              this._openBulkProductSelection(this._selectBy, rowIndex, record)
            }
          },
          width: 200
        },
        {
          type: 'string',
          name: 'productBrand',
          header: i18next.t('field.brand'),
          width: 100
        },
        {
          type: 'code',
          name: 'packingType',
          header: i18next.t('field.packing_type'),
          record: {
            codeName: 'PACKING_TYPES'
          },
          width: 100
        },
        {
          type: 'number',
          name: 'packingSize',
          header: i18next.t('field.packing_size'),
          width: 140
        },
        {
          type: 'string',
          name: 'uom',
          header: i18next.t('field.uom'),
          width: 100
        },
        {
          type: 'float',
          name: 'remainQty',
          header: i18next.t('field.available_qty'),
          width: 140
        },
        {
          type: 'float',
          name: 'releaseQty',
          header: i18next.t('field.release_qty'),
          imex: { header: i18next.t('field.release_qty'), key: 'releaseQty', width: 25, type: 'float' },
          record: { editable: true, options: { min: 0 } },
          width: 140
        },
        {
          type: 'string',
          name: 'remainUomValueWithUom',
          header: i18next.t('field.available_uom_value'),
          width: 140
        },
        {
          type: 'float',
          name: 'releaseUomValue',
          header: i18next.t('field.release_uom_value'),
          imex: { header: i18next.t('field.release_uom_value'), key: 'releaseUomValue', width: 25, type: 'float' },
          record: { editable: true, options: { min: 0 } },
          width: 140
        }
      ]
    }
  }

  _getStdDate() {
    let date = new Date()
    date.setDate(date.getDate())
    return date.toISOString().split('T')[0]
  }

  _validateDate(e) {
    let inputDate = e.currentTarget.value
    let todayDate = this._getStdDate()
    if (inputDate < todayDate) {
      this._showToast({
        message: 'Invalid date'
      })
    }
    return inputDate
  }

  _onInventoryFieldChanged(e) {
    let columnName = e.detail.column.name
    let roundedUomValue = e.detail.record.roundedUomValue || 0
    let releaseQty = 0

    if (columnName == 'releaseUomValue' || columnName == 'releaseQty' || columnName == 'inventory') {
      if (e.detail.record.isCrossDocking) return
      if (e.detail.record.groupType === GROUP_TYPES.BUNDLE.value) {
        this._productBundleName = `${e.detail.record.product.name}`
        this.fetchInventoriesByBundle(e.detail.record.product.id, e.detail.after)
      }

      if (columnName == 'inventory') {
        if (
          e.detail.after.remainUomValue &&
          e.detail.after.remainQty &&
          e.detail.after.remainUomValue > 0 &&
          e.detail.after.remainQty > 0
        ) {
          releaseQty = e.detail.record.releaseQty || 0

          roundedUomValue = releaseQty * (e.detail.after.remainUomValue / e.detail.after.remainQty)

          roundedUomValue = parseFloat(roundedUomValue.toFixed(3))
        }
      } else {
        let packageUomValue = e.detail.record.remainUomValue / e.detail.record.remainQty
        if (
          e.detail.record.remainUomValue &&
          e.detail.record.remainQty &&
          e.detail.record.remainUomValue > 0 &&
          e.detail.record.remainQty > 0
        ) {
          if (columnName === 'releaseQty') {
            releaseQty = parseFloat((e.detail.after || 0).toFixed(3))
          } else {
            releaseQty = Math.round(e.detail.after / packageUomValue)
          }

          roundedUomValue = releaseQty * packageUomValue
          roundedUomValue = parseFloat(roundedUomValue.toFixed(3))
          this.releaseQty = releaseQty
          this.releaseUomValue = roundedUomValue
        }
      }
    }

    this.inventoryData = {
      ...this.inventoryData,
      ...this.inventoryGrist.dirtyData,
      records: this.inventoryGrist.dirtyData.records.map((record, idx) => {
        if (
          (columnName == 'releaseUomValue' || columnName == 'releaseQty' || columnName == 'inventory') &&
          idx === e.detail.row
        ) {
          if (this.releaseQty > e.detail.record.remainQty && this.releaseUomValue > e.detail.record.releaseUomValue) {
            record.releaseQty = e.detail.record.releaseQty
            record.releaseUomValue = e.detail.record.releaseUomValue
          } else {
            record.releaseQty = releaseQty
            record.releaseUomValue = roundedUomValue
          }
        }

        let returnObj = {
          ...record,
          ...record.inventory,
          name: record.name ? record.name : idx
        }

        if (this._pickingStd === PICKING_STANDARD.SELECT_BY_PRODUCT.value) {
          returnObj = {
            ...returnObj,
            id: idx,
            product: {
              id: record?.inventory?.productId,
              name: record?.inventory?.productName
            },
            productDetail: {
              id: record?.inventory?.productDetailId
            }
          }
        }

        return returnObj
      })
    }

    this._updateInventoryGristConfig()
  }

  _onBundleFieldChanged(e) {
    const columnName = e.detail.column.name
    if (columnName === 'releaseQty' || columnName === 'releaseUomValue') {
      let totalReleaseQty = 0
      let totalReleaseUomValue = 0

      // get product id that related to current bundle
      let _productIds = this.bundleGrist.dirtyData.records.map(record => record.productId)
      _productIds = _productIds.filter((value, index) => _productIds.indexOf(value) === index)

      let productGroup = _productIds.map(id => {
        return {
          productId: id,
          productReleaseQty: 0,
          productReleaseUomValue: 0
        }
      })

      if (columnName === 'releaseQty') {
        this.bundleData = {
          ...this.bundleData,
          records: this.bundleGrist.dirtyData.records.map(record => {
            let releaseQty = record.releaseQty
            let releaseUomValue = (record.remainUomValue / record.remainQty) * record.releaseQty

            productGroup.forEach(group => {
              if (group.productId === record.productId) {
                releaseUomValue = Math.round(releaseUomValue * 100) / 100

                if (releaseQty > record.remainQty || Number.isNaN(releaseQty)) {
                  releaseQty = record.remainQty
                  releaseUomValue = record.remainUomValue
                } else if (releaseQty < 0) {
                  releaseQty = 0
                  releaseUomValue = 0
                }

                totalReleaseQty += releaseQty
                totalReleaseUomValue += releaseUomValue
              }
            })

            return {
              ...record,
              releaseQty,
              releaseUomValue,
              assigned: !!record.releaseQty
            }
          })
        }
      } else if (columnName === 'releaseUomValue') {
        this.bundleData = {
          records: this.bundleGrist.dirtyData.records.map(data => {
            let releaseQty = Math.round((data.remainQty * data.releaseUomValue) / data.uomValue)
            let releaseUomValue = data.releaseUomValue

            if (releaseUomValue > data.uomValue || Number.isNaN(releaseUomValue)) {
              releaseQty = data.remainQty
              releaseUomValue = data.uomValue
            } else if (releaseUomValue < 0) {
              releaseQty = 0
              releaseUomValue = 0
            }

            totalReleaseQty += releaseQty
            totalReleaseUomValue += releaseUomValue

            return {
              ...data,
              releaseQty: Math.round((releaseQty * data.uomValue) / data.uomValue),
              releaseUomValue,
              assigned: Boolean(data.releaseUomValue)
            }
          })
        }
      }
      this.releaseQty = totalReleaseQty
      this.releaseUomValue = Math.round(totalReleaseUomValue * 1000) / 1000
    }
  }

  async _onProductChangeHandler(event) {
    const changeRecord = event.detail.after
    const changedColumn = event.detail.column.name

    try {
      if (changedColumn === 'releaseQty') {
        this._validateReleaseQty(changeRecord.releaseQty, changeRecord.remainQty)
      } else if (changedColumn === 'releaseUomValue') {
        this._validateReleaseUomValue(changeRecord.releaseUomValue, changeRecord.remainUomValue)
      }
      this._updateInventoryGristConfig()
    } catch (e) {
      const beforeValue = event.detail.before && event.detail.before[event.detail.column.name]
      if (beforeValue) {
        event.detail.after[event.detail.column.name] = beforeValue
      } else {
        delete event.detail.after[event.detail.column.name]
      }
      this._showToast(e)
    }
  }

  _validateReleaseQty(releaseQty, remainQty) {
    if (remainQty === undefined) throw new Error(i18next.t('text.there_is_no_selected_items'))
    if (releaseQty > remainQty) {
      throw new Error(i18next.t('text.available_quantity_insufficient'))
    } else if (releaseQty <= 0) {
      throw new Error(i18next.t('text.invalid_quantity_input'))
    }
  }

  _validateReleaseUomValue(releaseUomValue, remainUomValue) {
    if (remainUomValue === undefined) throw new Error(i18next.t('text.there_is_no_selected_items'))
    if (releaseUomValue > remainUomValue) {
      throw new Error(i18next.t('text.available_uom_value_insufficient'))
    } else if (releaseUomValue <= 0) {
      throw new Error(i18next.t('text.invalid_uom_value_input'))
    }
  }

  _updateReleaseQtyUomValue(record) {
    this._releaseByBundleQty = record.releaseQty
    this._releaseByBundleUomValue = record.releaseUomValue
  }

  async fetchBizplaces() {
    const filters = []
    const response = await client.query({
      query: gql`
        query partnersBizplaces($filters: [Filter!]) {
          partnersBizplaces(filters: $filters) {
            items {
              id
              name
              description
            }
          }
        }
      `,
      variables: { filters }
    })

    if (!response.errors) {
      const bizplaces = response.data.partnersBizplaces.items
      if (bizplaces.length == 1) {
        this._bizplaceId = bizplaces[0].id
        this._bizplaceName = bizplaces[0].name

        this.switchPickingType()
      } else {
        this._bizplaceId = ''
        this._bizplaceName = ''
      }

      return bizplaces
    }
  }

  async fetchCountry() {
    const response = await client.query({
      query: gql`
        query geoCountriesWithoutParam {
          geoCountriesWithoutParam {
            items {
              id
              name
              description
            }
          }
        }
      `
    })

    if (!response.error) {
      this._allCountry = response.data.geoCountriesWithoutParam.items
    }
  }

  async fetchInventoriesByBundle(productBundleId, bundleReleaseQty) {
    const page = 1
    const limit = 99999
    const pagination = { page, limit }
    const filters = [
      {
        name: 'productBundleId',
        operator: 'eq',
        value: productBundleId
      },
      {
        name: 'bizplace_id',
        operator: 'eq',
        value: this._bizplaceId
      },
      {
        name: 'bundleReleaseQty',
        operator: 'eq',
        value: bundleReleaseQty
      }
    ]
    const sortings = []

    const response = await client.query({
      query: gql`
        query inventoriesByBundle($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
          inventoriesByBundle(filters: $filters, pagination: $pagination, sortings: $sortings) {
            bundleGroup {
              batchId
              bundleId
              bundleQty
              productId
              productDetailId
              productSku
              productName
              productDescription
              remainQty
              remainUomValue
              releaseQty
              releaseUomValue
              releaseUomValueWithUom
              packingType
              uom
            }
            bundleSetting {
              productId
              bundleId
              bundleQty
            }
          }
        }
      `,
      variables: {
        filters,
        pagination,
        sortings
      }
    })
    if (!response.errors) {
      const data = {
        records: response.data.inventoriesByBundle.bundleGroup.map(item => {
          return {
            ...item,
            product: `${item.productName} (${item.productDescription})`
          }
        })
      }

      const bundleSettingData = response.data.inventoriesByBundle.bundleSetting.map(setting => {
        return {
          ...setting,
          releaseQty: bundleReleaseQty * setting.bundleQty,
          productReleaseQty: 0,
          productReleaseUomValue: 0
        }
      })

      this.bundleData = {
        ...data
      }

      return data
    }
  }

  async _generateReleaseOrder() {
    try {
      this._paidAmount = this.paidAmountInput
      this._validateForm()
      this._validateInventories()

      let shippingOrderInfo = {}

      let contactPointInfo = this._serializeForm(this.shippingInfoForm)
      let contactPointPhone = contactPointInfo.phone1 ? contactPointInfo.phone1.replace(/\D/g, '') : null

      shippingOrderInfo = {
        ...contactPointInfo,
        phone1: contactPointPhone
      }

      delete shippingOrderInfo['']
      delete shippingOrderInfo.matchDeliveryAddressInput

      // If match delivery address is ticked, all the billing address info will be the same with delivery address info
      if (this._disableBillingAddress) {
        shippingOrderInfo.billingAddress = shippingOrderInfo.deliveryAddress1
        shippingOrderInfo.billingAddress2 = shippingOrderInfo.deliveryAddress2
        shippingOrderInfo.billingAddress3 = shippingOrderInfo.deliveryAddress3
        shippingOrderInfo.billingAddress4 = shippingOrderInfo.deliveryAddress4
        shippingOrderInfo.billingAddress5 = shippingOrderInfo.deliveryAddress5
        shippingOrderInfo.billingPostalCode = shippingOrderInfo.postalCode
        shippingOrderInfo.billingCountry = shippingOrderInfo.country
        shippingOrderInfo.billingCity = shippingOrderInfo.city
        shippingOrderInfo.billingState = shippingOrderInfo.state
      }

      let result = await CustomAlert({
        title: i18next.t('title.are_you_sure'),
        text: i18next.t('text.create_release_order'),
        confirmButton: { text: i18next.t('button.submit') },
        cancelButton: { text: i18next.t('button.cancel') }
      })

      if (!result.value) return

      if (this._crossDocking) {
        result = await CustomAlert({
          title: i18next.t('label.cross_docking'),
          text: i18next.t('text.create_release_order'),
          confirmButton: { text: i18next.t('button.submit') },
          cancelButton: { text: i18next.t('button.cancel') }
        })

        if (!result.value) return
      }

      let releaseGood = this._serializeForm(this.releaseOrderForm)
      delete releaseGood.warehouseTransport
      delete releaseGood.lmd

      releaseGood.orderInventories = await this._getOrderInventories()
      releaseGood.type = RO_TYPES.B2C.value
      releaseGood.orderMethod = this._pickingStd
      releaseGood.exportOption = false
      releaseGood.lmdOption = this._isLmd
      releaseGood.courierOption = true
      releaseGood.packingOption = true
      releaseGood.paidAmount = parseFloat(this._paidAmount.value)
      //releaseGood.phone1 =

      delete releaseGood.bizplaceId
      delete releaseGood.bizplaceName

      const response = await client.mutate({
        mutation: gql`
          mutation ($releaseGood: NewReleaseGood, $invoiceAttachment: [Upload!], $awbAttachment: [Upload!]) {
            generateReleaseGood(
              releaseGood: $releaseGood
              awbAttachment: $awbAttachment
              invoiceAttachment: $invoiceAttachment
            ) {
              id
              name
            }
          }
        `,
        variables: {
          releaseGood: {
            ...releaseGood,
            ...(shippingOrderInfo || {}),
            partnerBizplaceId: this._bizplaceId
          },
          //if user uploads AWB first and then checks LMD option, remove AWB
          awbAttachment: this._isLmd ? undefined : this._awbDocument?.files ? this._awbDocument.files : undefined,
          invoiceAttachment: this._invoiceDocument?.files ? this._invoiceDocument.files : undefined
        },
        context: { hasUpload: true }
      })

      if (!response.errors) {
        this.resetPage()
        this.resetOption()
        this._resetShippingInfoForm()
        this.__inventoryData = []
        this._deliveryPostCode = []
        this._billingPostCode = []
        this._selectedPostCode = ''
        this._selectedBillingPostCode = ''
        this._clearView()

        navigate(`b2c_release_order_detail/${response.data.generateReleaseGood.name}`)
        this._showToast({ message: i18next.t('text.release_order_created') })
      } else {
        let overLimitError = response.errors.find(err => err?.extensions?.exception?.errorCode == 'rol1')
        if (overLimitError) {
          let refreshData = JSON.parse(overLimitError.extensions.exception.detail.data)

          let data = this.inventoryData.records
          refreshData.forEach(dt => {
            let idx = data.findIndex(
              x => x.productId == dt.productId && x.batchId == dt.batchId && x.packingType == dt.packingType
            )

            if (idx >= 0) {
              data[idx].remainQty = dt.availableQty
              data[idx].inventory.remainQty = dt.availableQty
              data[idx].remainUomValue = dt.availableUomValue
              data[idx].inventory.remainUomValue = dt.availableUomValue
              data[idx].isError = data[idx].releaseQty > dt.availableQty
              data[idx].remainUomValueWithUom = `${dt.availableUomValue} ${dt.uom}`
              data[idx].inventory.remainUomValueWithUom = `${dt.availableUomValue} ${dt.uom}`
            }
          })

          this.inventoryData = {
            ...this.inventoryData,
            records: data
          }
        }
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  _validateForm() {
    if (!this.releaseOrderForm.checkValidity()) {
      throw new Error(i18next.t('text.release_order_form_invalid'))
    }

    if (this._isCod) {
      if (!this._paidAmount.value) {
        throw new Error(i18next.t('text.paid_amount_is_empty_please_fill_in_the_data_to_proceed_creating_order'))
      }
    }

    if (this._isLmd) {
      const checkShipmentFields = (
        attentionToInput,
        postalCodeInput,
        stateInput,
        cityInput,
        addressInput,
        contactInput
      ) => {
        if (
          !attentionToInput.value &&
          !postalCodeInput.value &&
          !stateInput.value &&
          !cityInput.value &&
          !addressInput.value &&
          !contactInput.value
        ) {
          throw new Error(i18next.t('text.please_fill_in_the_shipping_information_in_shipment_tab'))
        }

        if (!attentionToInput.value) {
          throw new Error(i18next.t('text.attention_to_is_empty_please_fill_in_the_data_before_proceed_create_order'))
        }

        if (!postalCodeInput.value) {
          throw new Error(
            i18next.t('text.zip/postal_code_is_empty_please_fill_in_the_data_before_proceed_create_order')
          )
        }

        if (!stateInput.value) {
          throw new Error(i18next.t('text.state_is_empty_please_fill_in_the_data_before_proceed_create_order'))
        }

        if (!cityInput.value) {
          throw new Error(i18next.t('text.city_is_empty_please_fill_in_the_data_before_proceed_create_order'))
        }

        if (!addressInput.value) {
          throw new Error(
            i18next.t('text.delivery_address_is_empty_please_fill_in_the_data_before_proceed_create_order')
          )
        }

        if (!contactInput.value) {
          throw new Error(i18next.t('text.contact_is_empty_please_fill_in_the_data_before_proceed_create_order'))
        }
      }

      if (this.deliveryCountryInput.value == 'MY') {
        checkShipmentFields(
          this.attentionToInput,
          this.deliveryPostalCodeSelectInput,
          this.deliveryStateInput,
          this.deliveryCityInput,
          this.deliveryAddressInput,
          this.deliveryContactInput
        )
      } else {
        checkShipmentFields(
          this.attentionToInput,
          this.deliveryPostalCodeInput,
          this.deliveryStateInput,
          this.deliveryCityInput,
          this.deliveryAddressInput,
          this.deliveryContactInput
        )
      }

      // if (!this.matchDeliveryAddressInput.checked) {
      //   if (this.billingCountryInput.value == 'MY') {
      //     checkShipmentFields(
      //       this.billingPostalCodeSelectInput,
      //       this.billingStateInput,
      //       this.billingCityInput,
      //       this.billingAddressInput
      //     )
      //   } else if (!this.billingCountryInput.value == 'MY') {
      //     checkShipmentFields(
      //       this.billingPostalCodeInput,
      //       this.billingStateInput,
      //       this.billingCityInput,
      //       this.billingAddressInput
      //     )
      //   }
      // }
      if (!this._disableBillingAddress && !this.billingAddressInput.value && !this.matchDeliveryAddressInput.checked) {
        throw new Error(i18next.t('text.billing_address_is_empty_please_fill_in_the_data_before_proceed_create_order'))
      }
    }

    if (this.shippingOrderForm && !this.shippingOrderForm.checkValidity()) {
      throw new Error(i18next.t('text.shipping_order_form_invalid'))
    }

    if (this._invoiceDocument?.files?.length > 1) {
      throw new Error(i18next.t('text.only_one_file_is_allowed_for_both_invoice_upload'))
    }

    if (this._awbDocument?.files?.length > 1) {
      throw new Error(i18next.t('text.only_one_file_is_allowed_for_both_AWB_upload'))
    }
  }

  _validateInventories() {
    const inventories = this.inventoryGrist?.dirtyData?.records
    if (!inventories?.length) throw new Error(i18next.t('text.no_products'))
    // required field (batchId, packingType, uomValue, unit, packQty)
    if (!inventories.every(record => record.releaseQty && record.batchId && record.packingType)) {
      throw new Error(i18next.t('text.empty_value_in_list'))
    }

    if (inventories.some(({ releaseQty }) => releaseQty < 0)) {
      throw new Error(i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.release_qty') } }))
    }

    if (inventories.some(({ releaseUomValue }) => releaseUomValue < 0)) {
      throw new Error(i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.release_uom_value') } }))
    }

    if (inventories.some(record => record.releaseQty > record.remainQty)) {
      throw new Error(i18next.t('text.invalid_quantity_input'))
    }

    if (inventories.some(record => record.isInventoryDecimal === false && record.releaseQty % 1 !== 0)) {
      const invalidRecord = inventories.find(
        record => record.isInventoryDecimal === false && record.releaseQty % 1 !== 0
      )
      throw new Error(i18next.t('text.decimal_quantities_not_allowed_for_sku', { sku: invalidRecord.productSKU }))
    }

    if (this._pickingStd === PICKING_STANDARD.SELECT_BY_PALLET.value) {
      // duplication of pallet id
      const palletIds = inventories.map(inv => inv.palletId)
      if (palletIds.some((palletId, idx, palletIds) => palletIds.indexOf(palletId) !== idx)) {
        throw new Error(i18next.t('text.lot_id_is_duplicated'))
      }
    }

    if (inventories.some(record => record.locationType == 'DAMAGE') && recall == false) {
      throw new Error(i18next.t('text.there_are_damaged_inventories'))
    }
  }

  async _openBulkProductSelection(type, rowIndex, record) {
    if (this._bizplaceId) {
      openPopup(
        html`
          <select-inventory-popup
            .bizplaceId="${this._bizplaceId}"
            .selectMultipleProducts="${true}"
            .switchTypePane="${type}"
            .inventoryData="${this.inventoryGrist.dirtyData.records}"
            @selected="${e => {
              let newRecords = []
              for (let i = 0; i < e.detail.multipleProducts.length; i++) {
                newRecords.push(e.detail.multipleProducts[i])
              }

              if (newRecords.length > 1) {
                this.inventoryData = {
                  ...this.inventoryData,
                  records: [...this.inventoryGrist.dirtyData.records, ...newRecords]
                }
              } else {
                // update existing inventory data records
                this.inventoryGrist.dirtyData.records.splice(rowIndex, 1, {
                  ...this.inventoryGrist.dirtyData.records[rowIndex],
                  ...newRecords[0]
                })
                this.inventoryData = {
                  ...this.inventoryData,
                  records: [...this.inventoryGrist.dirtyData.records]
                }
              }
            }}"
          ></select-inventory-popup>
        `,
        {
          backdrop: true,
          size: 'large',
          title: i18next.t('title.select_item')
        }
      )
    } else {
      this._showToast({ message: i18next.t('text.company_selection_is_empty') })
    }
  }

  _updateInventoryGristConfig() {
    if (this._pickingStd === PICKING_STANDARD.SELECT_BY_PRODUCT.value) {
      const _selectedInv = (this.inventoryGrist.dirtyData.records || [])
        .filter(record => !record.isCrossDocking)
        .map(record => {
          return {
            batchId: record?.inventory?.batchId,
            packingType: record?.inventory?.packingType,
            packingSize: record?.inventory?.packingSize,
            productId: record?.inventory?.productId,
            productDetailId: record?.inventory?.productDetailId,
            groupType: record?.inventory?.groupType,
            releaseQty: record.releaseQty || 0,
            releaseUomValue: record.releaseUomValue || 0
          }
        })

      this.inventoryGristConfig = {
        ...this.inventoryGristConfig,
        columns: this.inventoryGristConfig.columns.map(column => {
          if (column.name === 'inventory') {
            column.record.options.basicArgs = {
              ...column.record.options.basicArgs,
              filters: [
                ...column.record.options.basicArgs.filters.filter(
                  filter => filter.name !== 'batch_product' && filter.name !== 'batch_bundle'
                )
              ]
            }

            if (_selectedInv.length) {
              const _selectedSingleInv = _selectedInv.filter(inv => inv.groupType === GROUP_TYPES.SINGLE.value)
              const _selectedBundleInv = _selectedInv.filter(inv => inv.groupType === GROUP_TYPES.BUNDLE.value)

              if (_selectedSingleInv.length)
                column.record.options.basicArgs.filters.push({
                  name: 'batch_product',
                  value: _selectedSingleInv,
                  operator: 'notin'
                })

              if (_selectedBundleInv.length)
                column.record.options.basicArgs.filters.push({
                  name: 'batch_bundle',
                  value: _selectedBundleInv,
                  operator: 'notin'
                })
            }
          }

          return column
        })
      }
    } else {
      const _selectedInventories = (this.inventoryGrist.dirtyData.records || []).map(record => record.inventory.id)
      this.inventoryGristConfig = {
        ...this.inventoryGristConfig,
        columns: this.inventoryGristConfig.columns.map(column => {
          if (column.name === 'inventory') {
            column.record.options.basicArgs = {
              ...column.record.options.basicArgs,
              filters: [...column.record.options.basicArgs.filters.filter(filter => filter.name !== 'id')]
            }

            if (_selectedInventories.length)
              column.record.options.basicArgs.filters = [
                ...column.record.options.basicArgs.filters,
                {
                  name: 'id',
                  value: _selectedInventories,
                  operator: 'notin'
                }
              ]
          }

          return column
        })
      }
    }
  }

  _clearGristConditions() {
    if (this.inventoryGristConfig?.columns?.length) {
      this.inventoryGristConfig = {
        ...this.inventoryGristConfig,
        columns: this.inventoryGristConfig.columns.map(column => {
          if (column.name === 'inventory') {
            column.record.options.basicArgs = {
              filters: column.record.options.basicArgs.filters.filter(
                filter => filter.name !== 'batch_product' && filter.name !== 'id'
              )
            }
          }

          return column
        })
      }
    }
  }

  async _getOrderInventories() {
    const bundleOrderInventories = []

    //// Note: need to relook into the logic. Might get performance issue when theres many order, client server round trip too many.
    await Promise.all(
      this.inventoryGrist.data.records
        .filter(
          record =>
            this._pickingStd === PICKING_STANDARD.SELECT_BY_PRODUCT.value &&
            record.inventory.groupType === GROUP_TYPES.BUNDLE.value
        )
        .map(async record => {
          let bundleReleaseDetail = await this.fetchInventoriesByBundle(record.inventory.productId, record.releaseQty)
          bundleReleaseDetail = bundleReleaseDetail.records.map(item => {
            return {
              product: { id: item.productId, name: item.productName },
              productDetail: { id: item.productDetailId },
              batchId: item.batchId,
              packingType: item.packingType,
              packingSize: item.packingSize,
              type: ORDER_TYPES.RELEASE_OF_GOODS.value,
              status: ORDER_INVENTORY_STATUS.PENDING.value,
              releaseQty: item.releaseQty,
              releaseUomValue: item.releaseUomValue,
              uom: item.uom
            }
          })
          bundleOrderInventories.push(...bundleReleaseDetail)
        })
    )

    const singleOrderInventories = this.inventoryGrist.data.records
      .filter(record => record.inventory.groupType !== GROUP_TYPES.BUNDLE.value)
      .map(record => {
        let newRecord = {
          releaseQty: record.releaseQty,
          releaseUomValue: record.releaseUomValue,
          batchId: record.inventory.batchId,
          batchIdRef: record.inventory.batchIdRef,
          packingType: record.inventory.packingType,
          packingSize: record.inventory.packingSize,
          type: ORDER_TYPES.RELEASE_OF_GOODS.value,
          status: ORDER_INVENTORY_STATUS.PENDING.value,
          uom: record.inventory.uom
        }

        if (record.isCrossDocking) newRecord.crossDocking = true

        if (this._pickingStd === PICKING_STANDARD.SELECT_BY_PRODUCT.value) {
          newRecord.product = {
            id: record.inventory.productId,
            name: record.inventory.productName
          }
          newRecord.productDetail = {
            id: record.inventory.productDetailId
          }
        } else {
          newRecord.product = {
            id: record.inventory.productId || record.inventory.product.id,
            name: record.inventory.productName || record.inventory.product.name
          }
          newRecord.productDetail = {
            id: record.inventory.productDetailId || record.inventory.productDetail.id
          }
          newRecord.inventory = { id: record.id }
        }

        return newRecord
      })

    let orderInventories = [...bundleOrderInventories, ...singleOrderInventories]

    if (this._pickingStd === PICKING_STANDARD.SELECT_BY_PRODUCT.value) {
      // return the merged bundle and single order inventories
      let data = orderInventories.reduce((acc, curr) => {
        let exsitingDataIndex = acc.findIndex(
          x => x.product.id === curr.product.id && x.batchId === curr.batchId && x.packingType === curr.packingType
        )

        if (exsitingDataIndex >= 0) {
          acc[exsitingDataIndex].releaseQty += curr.releaseQty
          acc[exsitingDataIndex].releaseUomValue += curr.releaseUomValue
        } else {
          acc.push({ ...curr })
        }

        return acc
      }, [])

      return data
    } else {
      return orderInventories
    }
  }

  _validateCountry(e) {
    if (e.target.value != 'MY') {
      this._switchDeliveryCountryInput = true
    } else {
      this._switchDeliveryCountryInput = false
    }
  }

  _validateBillingCountry(e) {
    if (e.target.value != 'MY') {
      this._switchBillingCountryInput = true
      this._selectedBillingCountry = e.target.value
    } else {
      this._switchBillingCountryInput = false
      this._selectedBillingCountry = e.target.value
    }
  }

  async _getAllPostCode() {
    try {
      const response = await client.query({
        query: gql`
          query geoAreasAllPostCode {
            geoAreasAllPostCode {
              items {
                postalCode
              }
              total
            }
          }
        `
      })

      if (!response.errors) {
        const items = response.data.geoAreasAllPostCode.items
        this._deliveryPostCode = items
        this._billingPostCode = items
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  async _getStateAndCityByPostCode(value, name) {
    const postCode = value

    // If user select the first empty postal code, the city and state will change to empty
    if (postCode == '') {
      if (name == 'postalCode') {
        this._cityInput.value = ''
        this._stateInput.value = ''
        return
      } else if (name == 'billingPostalCode') {
        this._cityBillingInput.value = ''
        this._stateBillingInput.value = ''
        return
      }
    }

    try {
      const response = await client.query({
        query: gql`
          query geoAreasGetStateAndCityByPosCode($postCode: String!) {
            geoAreasGetStateAndCityByPosCode(postCode: $postCode) {
              stateName
              cityName
            }
          }
        `,
        variables: {
          postCode
        }
      })

      if (!response.errors) {
        const { stateName, cityName } = response.data.geoAreasGetStateAndCityByPosCode

        switch (name) {
          case 'postalCode':
            this._deliveryCity = cityName.toUpperCase()
            this._deliveryState = stateName
            break

          case 'billingPostalCode':
            this._billingCity = cityName.toUpperCase()
            this._billingState = stateName

          default:
            break
        }
      }
    } catch (error) {
      this._showToast(e)
    }
  }

  _serializeForm(form) {
    let obj = {}
    Array.from(form.querySelectorAll('input, select,textarea')).forEach(field => {
      if (!field.hasAttribute('hidden') && field.value) {
        obj[field.name] = field.type === 'checkbox' ? field.checked : field.value
      }
    })

    return obj
  }

  checkInventoryValidity() {
    const inventories = this.inventoryGrist?.dirtyData?.records
    if (!inventories?.length) throw new Error(i18next.t('text.there_is_no_inventory'))

    if (this._pickingStd === PICKING_STANDARD.SELECT_BY_PALLET && inventories.some(record => !record?.inventory?.id))
      throw new Error(i18next.t('text.invalid_inventory'))

    if (inventories.some(record => !record.releaseQty)) throw new Error(i18next.t('text.invalid_release_qty'))
  }

  _openBizplacesSelector() {
    openPopup(
      html`
        <popup-partner-bizplaces-selector
          @selected="${e => {
            this._bizplaceId = e.detail.id
            this._bizplaceName = e.detail.name
            this.switchPickingType()
            this.inventoryGrist.reset()
            this._clearView()
            // this._resetShippingInfoForm()
            this.fetchCountry()
          }}"
        ></popup-partner-bizplaces-selector>
      `,
      {
        backdrop: true,
        size: 'large',
        title: i18next.t('title.select_company')
      }
    )
  }

  async bulkUploadValidateWarehousePartnersProductsQuantity(orderInventories) {
    const response = await client.query({
      query: gql`
        query bulkUploadValidateWarehousePartnersProductsQuantity(
          $orderInventories: [NewOrderInventory!]
          $partnerBizplaceId: String!
        ) {
          bulkUploadValidateWarehousePartnersProductsQuantity(
            orderInventories: $orderInventories
            partnerBizplaceId: $partnerBizplaceId
          ) {
            id
            name
            description
            batchId
            batchIdRef
            productId
            productDetailId
            productSKU
            productName
            remainQty
            remainUomValue
            remainUomValueWithUom
            packingType
            packingSize
            uom
            releaseQty
            releaseUomValue
            isError
            groupType
            inventory {
              batchId
              batchIdRef
              productId
              productDetailId
              productSKU
              productName
              remainQty
              remainUomValue
              remainUomValueWithUom
              packingType
              packingSize
              uom
            }
            product {
              id
              name
              sku
            }
            productDetail {
              id
            }
          }
        }
      `,
      variables: { orderInventories, partnerBizplaceId: this._bizplaceId }
    })

    if (!response.errors) {
      const data = response.data.bulkUploadValidateWarehousePartnersProductsQuantity
      this.inventoryGrist.dirtyData.records = data.records
      this.inventoryData = {
        ...this.inventoryData,
        ...this.inventoryGrist.dirtyData,
        records: data.map((dt, idx) => {
          return {
            ...dt,
            id: idx,
            name: idx,
            __dirty__: '+'
          }
        })
      }

      this._updateInventoryGristConfig()
    }
  }

  getExcelColumns() {
    return [
      {
        type: 'string',
        name: 'productSKU',
        header: i18next.t('field.sku'),
        imex: { header: i18next.t('field.sku'), key: 'productSKU', width: 25, type: 'string' },
        width: 100
      },
      {
        type: 'string',
        name: 'packingType',
        header: i18next.t('field.packing_type'),
        imex: {
          header: i18next.t('field.packing_type'),
          key: 'packingType',
          width: 20,
          type: 'string'
        },
        width: 150
      },
      {
        type: 'integer',
        name: 'releaseQty',
        header: i18next.t('field.release_qty'),
        imex: { header: i18next.t('field.release_qty'), key: 'releaseQty', width: 25, type: 'float' },
        width: 140
      }
    ]
  }

  async _exportableData() {
    try {
      var headerSetting = [
        ...this.getExcelColumns()
          .filter(column => column.type !== 'gutter' && column.imex !== undefined)
          .map(column => {
            return column.imex
          })
      ]

      return { header: headerSetting, data: [] }
    } catch (e) {
      this._showToast(e)
    }
  }

  async importHandler(patches) {
    try {
      const orderInventories = patches.reduce((acc, patch) => {
        delete patch.cuFlag
        let idxExistingData = acc.findIndex(i => i.productSKU == patch.productSKU && i.packingType == patch.packingType)

        if (idxExistingData >= 0) {
          acc[idxExistingData].releaseQty = acc[idxExistingData].releaseQty + patch.releaseQty
        } else {
          acc.push(patch)
        }
        return acc
      }, [])

      // validate releaseQty
      // only positive integers permitted
      for (const orderInventory of orderInventories) {
        const rQty = orderInventory.releaseQty
        if (!Number.isInteger(rQty)) throw new Error(`${rQty} ${i18next.t('text.is_not_an_integer')}`)
        if (rQty <= 0) throw new Error(i18next.t('text.release_qty_must_be_at_least_1'))

        delete orderInventory.id
      }

      this.inventoryData = {
        records: [...patches]
      }

      await this.bulkUploadValidateWarehousePartnersProductsQuantity(orderInventories)

      history.back()
    } catch (e) {
      this._showToast(e)
    }
  }

  async _importableData(records) {
    try {
      if (this._pickingStd === PICKING_STANDARD.SELECT_BY_PRODUCT.value) {
        if (this._bizplaceId) {
          records = records
            .filter(record => record.productSKU)
            .map(record => {
              return {
                ...record,
                releaseQty: parseFloat(record.releaseQty) || null
              }
            })

          let inventoryGristConfigExcel = {
            pagination: { infinite: true },
            rows: {
              selectable: { multiple: true, appendable: false },
              classifier: (record, rowIndex) => {
                return {
                  emphasized: record.isCrossDocking
                }
              }
            },
            list: { fields: ['productSKU', 'packingType', 'releaseQty'] },
            columns: this.getExcelColumns()
          }

          openPopup(
            html`
              <import-pop-up
                .records=${records}
                .config=${{
                  rows: inventoryGristConfigExcel.rows,
                  columns: [...inventoryGristConfigExcel.columns.filter(column => column.imex !== undefined)]
                }}
                .importHandler="${await this.importHandler.bind(this)}"
              ></import-pop-up>
            `,
            {
              backdrop: true,
              escapable: false,
              size: 'large',
              title: i18next.t('title.import')
            }
          )
        } else {
          throw new Error(i18next.t('text.please_select_a_company'))
        }
      } else {
        throw new Error(`Excel import only available for Select By Product`)
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  async _tabChange(key) {
    if (key == 'order') {
      this._showReleasedOrderInfo = false
      this._showShippingInfo = true
    } else if (key == 'shipment') {
      this._showReleasedOrderInfo = true
      this._showShippingInfo = false
    }
  }

  _fillUpDeliveryInfo(data) {
    // remapping according release good table
    const remapData = {
      attentionCompany: data.companyName || '',
      attentionTo: data.name || '',
      city: data.city || '',
      state: data.state || '',
      postalCode: data.postCode || '',
      country: 'MY',
      phone1: data.phone || '',
      deliveryAddress1: data.address ? data.address : '' + data.address2 ? data.address2 : '',
      billingAddress: data.billingAddress
    }

    this._selectedPostCode = data.postCode

    this._fillupForm(this.shippingInfoForm, remapData)
  }

  _resetShippingInfoForm() {
    this.shippingInfoForm.reset()
  }

  _resetExportInfoForm() {
    this._containerClosureDate = ''
  }

  _fillupForm(form, data) {
    if (form) {
      form.reset()
      for (let key in data) {
        Array.from(form.querySelectorAll('input, textarea', 'select')).forEach(field => {
          if (field.name === key && field.type === 'checkbox') {
            field.checked = data[key]
          } else if (field.name === key && field.type === 'datetime-local') {
            const datetime = Number(data[key])
            const timezoneOffset = new Date(datetime).getTimezoneOffset() * 60000
            field.value = new Date(datetime - timezoneOffset).toISOString().slice(0, -1)
          } else if (field.name === key) {
            if (data[key] instanceof Object) {
              const objectData = data[key]
              field.value = `${objectData.name} ${objectData.description ? `(${objectData.description})` : ''}`
            } else {
              field.value = data[key]
            }
          }
        })
      }
    }
  }

  async checkActiveLmd() {
    const response = await client.query({
      query: gql`
        query checkActiveLastMileDelivery {
          checkActiveLastMileDelivery
        }
      `
    })

    if (!response.error) {
      this._isLmdExists = response.data.checkActiveLastMileDelivery
    }
  }

  sortByNameField(items, nameField, nameField2) {
    if (nameField2) {
      items?.sort((a, b) => {
        if (a[nameField] == b[nameField]) {
          return a[nameField2] > b[nameField2] ? 1 : a[nameField2] < b[nameField2] ? -1 : 0
        } else {
          return a[nameField] > b[nameField] ? 1 : a[nameField] < b[nameField] ? -1 : 0
        }
      })
    } else {
      items?.sort((a, b) => (a[nameField] > b[nameField] ? 1 : a[nameField] < b[nameField] ? -1 : 0))
    }

    return items
  }

  _showToast({ type, message }) {
    document.dispatchEvent(
      new CustomEvent('notify', {
        detail: {
          type,
          message
        }
      })
    )
  }
}
window.customElements.define('create-b2c-release-order', CreateB2CReleaseOrder)
