import '@things-factory/barcode-ui'
import '@things-factory/grist-ui'
import './undo-putaway-popup'
import '../select-location-popup'
import '../../components/worksheet-information-popup'
import './putaway-same-carton-popup'
import './putaway-replenishment-inventory-popup'
import './putaway-replenishment-same-product-popup'

import gql from 'graphql-tag'
import { css, html } from 'lit-element'
import { connect } from 'pwa-helpers/connect-mixin.js'

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

import { fetchSettingRule } from '../../../fetch-setting-value'
import { ARRIVAL_NOTICE, CUSTOMER_RETURN, REPLENISHMENT, WAREHOUSE_RETURN, WORKSHEET_STATUS, CONDITION_OF_GOODS } from '../../constants'

const OPERATION_TYPE = {
  PUTAWAY: 'putaway',
  TRANSFER: 'transfer'
}

const AVAIL_ORDER_TYPES = { ARRIVAL_NOTICE, CUSTOMER_RETURN, WAREHOUSE_RETURN, REPLENISHMENT }

class PutawayProduct extends connect(store)(localize(i18next)(PageView)) {
  static get properties() {
    return {
      config: Object,
      data: Object,
      orderProductData: Object,
      incompleteLocationName: Boolean,
      locations: Array,
      orderNo: String,
      refOrderType: String,
      recommendLocationName: String,
      customerCompanyDomainId: String,
      _bizplaceName: String,
      _enableCartonLabel: Boolean,
      _expirationDate: Number,
      __minInboundShelfLife: Number,
      _locationType: String,
      _operationType: String,
      _orderNo: String,
      _cartonId: String,
      _replenishmentId: String,
      _productName: String,
      _productSku: String,
      _selectedTaskStatus: String,
      _scanning: Boolean,
      _worksheetInfo: Object,
      _records: Array,
      _selectedLocation: String,
      _pageSettings: Object,
      _enableProductScanning: Boolean
    }
  }

  static get styles() {
    return [
      MultiColumnFormStyles,
      css`
        data-grist {
          overflow: auto;
          flex: 1;
        }
        #form-section {
          background-color: white;
        }
        :host {
          display: flex;
          flex-direction: column;
          overflow: hidden;
        }
        h2 {
          padding: var(--subtitle-padding);
          font: var(--subtitle-font);
          color: var(--subtitle-text-color);
          border-bottom: var(--subtitle-border-bottom);
        }
        legend mwc-icon {
          vertical-align: middle;
          margin: var(--grist-title-icon-margin);
          font-size: var(--grist-title-icon-size);
          color: var(--grist-title-icon-color);
          cursor: pointer;
        }
      `
    ]
  }

  get context() {
    var actions = []
    this.incompleteLocationName = false

    if (
      this.data.records.some(record => record.completed) &&
      this.refOrderType !== AVAIL_ORDER_TYPES.WAREHOUSE_RETURN.value
    ) {
      actions.push({
        title: i18next.t('button.undo'),
        action: this._openUndoPopup.bind(this),
        ...CommonButtonStyles.undo
      })
    }

    if (this.completed) {
      actions.push({
        title: i18next.t('button.complete'),
        action: this._completeHandler.bind(this),
        ...CommonButtonStyles.submit
      })
    }

    return {
      title: i18next.t('title.putaway'),
      help: 'operato-wms/inbound/putaway-product',
      actions
    }
  }

  get gristConfig() {
    let columns = [
      { type: 'gutter', gutterName: 'sequence' },
      {
        type: 'gutter',
        gutterName: 'button',
        icon: 'reorder',
        handlers: {
          click: (columns, data, column, record, rowIndex, _orderNo) => {
            this._openReplenishmentPutawayInventoriesPopup(this._replenishmentId, record.inventory.id)
          }
        },
        exclude: this.refOrderType != AVAIL_ORDER_TYPES.REPLENISHMENT.value
      },
      {
        type: 'boolean',
        name: 'completed',
        header: i18next.t('field.completed'),
        width: 40
      },
      {
        type: 'string',
        name: 'palletId',
        header: i18next.t('field.lot_id'),
        width: 140
      },
      {
        type: 'string',
        name: 'cartonId',
        header: i18next.t('field.carton_id'),
        width: 140
      },
      {
        type: 'string',
        name: 'sku',
        label: true,
        header: i18next.t('field.sku'),
        width: 120
      },
      {
        type: 'object',
        name: 'product',
        header: i18next.t('field.product'),
        width: 140
      },
      {
        type: 'string',
        name: 'batchId',
        header: i18next.t('field.batch_id'),
        width: 140
      },
      {
        type: 'string',
        name: 'packingType',
        header: i18next.t('field.packing_type'),
        width: 140
      },
      {
        type: 'string',
        name: 'packingSize',
        header: i18next.t('field.packing_size'),
        width: 140
      },
      {
        type: 'date',
        name: 'expirationDate',
        header: i18next.t('field.exp_date'),
        width: 140
      },
      {
        type: 'float',
        name: 'qty',
        header: i18next.t('field.qty'),
        width: 80
      },
      {
        type: 'string',
        name: 'displayConditionOfGoods',
        label: true,
        header: i18next.t('field.type_of_condition'),
        width: 150
      },
      {
        type: 'object',
        name: 'reusablePallet',
        header: i18next.t('field.reusable_pallet'),
        width: 140
      },
      {
        type: 'object',
        name: 'location',
        header: i18next.t('field.location'),
        width: 140
      }
    ]

    return {
      rows: {
        appendable: false,
        handlers: {
          click: async (columns, data, column, record, rowIndex) => {
            if (data.records.length && record) {
              if (this._selectedOrderProduct && this._selectedOrderProduct.name === record) {
                return
              }

              this._selectedOrderProduct = record
              this._selectedTaskStatus = null
              this._selectedTaskStatus = record.status
              this.recommendLocationName = null

              if (
                !record.completed &&
                this.refOrderType !== AVAIL_ORDER_TYPES.WAREHOUSE_RETURN.value &&
                this.refOrderType !== AVAIL_ORDER_TYPES.REPLENISHMENT.value
              ) {
                this.recommendLocationName = (await this._getLocationRecommendation(record.name)) || null
              }

              if (this._enableCartonLabel && record?.cartonId) this._focusOnCartonInput()
              else this._focusOnPalletInput()
            }
          }
        }
      },
      pagination: { infinite: true },
      list: {
        fields: ['completed', 'sku', 'product', 'palletId', 'cartonId', 'expirationDate', 'batchId', 'qty', 'displayConditionOfGoods', 'location']
      },
      columns: columns.filter(itm => itm.exclude != true)
    }
  }

  get cartonInput() {
    return this.shadowRoot.querySelector('barcode-scanable-input[name=cartonId]')
  }

  get palletInput() {
    return this.shadowRoot.querySelector('barcode-scanable-input[name=palletId]')
  }

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

  get infoForm() {
    return this.shadowRoot.querySelector('form#info-form')
  }

  get inputForm() {
    return this.shadowRoot.querySelector('form#input-form')
  }

  get locationInput() {
    return this.shadowRoot.querySelector('barcode-scanable-input[name=locationCode]')?.shadowRoot.querySelector('input')
  }

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

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

  get orderNoInput() {
    return this.shadowRoot.querySelector('barcode-scanable-input[name=orderNo]').shadowRoot.querySelector('input')
  }

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

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

  get toPalletInput() {
    return this.shadowRoot.querySelector('barcode-scanable-input[name=toPalletId]').shadowRoot.querySelector('input')
  }

  get productBarcodeInput() {
    return this.shadowRoot.querySelector('barcode-scanable-input[name=productBarcode]')
  }

  getInput = inputSelector => {
    return inputSelector?.shadowRoot.querySelector('input')
  }

  render() {
    return html`
      <form id="info-form" class="multi-column-form">
        <fieldset>
          <label>${i18next.t('label.order_type')}</label>
          <select name="orderType" @change="${this.orderTypeChangeHandler.bind(this)}">
            ${Object.keys(AVAIL_ORDER_TYPES).map(key =>
              this.refOrderType === AVAIL_ORDER_TYPES[key].value
                ? html`
                    <option value="${AVAIL_ORDER_TYPES[key].value}" selected>
                      ${i18next.t(`label.${AVAIL_ORDER_TYPES[key].name}`)}
                    </option>
                  `
                : html`
                    <option value="${AVAIL_ORDER_TYPES[key].value}">
                      ${i18next.t(`label.${AVAIL_ORDER_TYPES[key].name}`)}
                    </option>
                  `
            )}
          </select>

          <label>${i18next.t('label.order_no')}</label>
          <barcode-scanable-input
            name="orderNo"
            custom-input
            @keypress="${async e => {
              if (e.keyCode === 13) {
                e.preventDefault()
                if (this.orderNoInput.value) {
                  this._fetchProducts(this.orderNoInput.value)
                  this.incompleteLocationName = false
                  this.updateContext()
                }
              }
            }}"
          ></barcode-scanable-input>
        </fieldset>
      </form>

      <form id="input-form" class="multi-column-form">
        <fieldset>
          ${this.recommendLocationName
            ? html` <label>${i18next.t('label.recommend_location')}</label>
                <input name="recommendLocation" type="text" value=${this.recommendLocationName} readonly />`
            : html``}
          ${this._enableCartonLabel
            ? html` ${this.refOrderType === AVAIL_ORDER_TYPES.REPLENISHMENT.value && this._enableProductScanning
                ? html` <label>${i18next.t('label.product_barcode')}</label>
                    <barcode-scanable-input
                      name="productBarcode"
                      without-enter
                      custom-input
                      ?scan-only=${this._pageSettings?.cameraScanOnly}
                      @keypress="${async e => {
                        if (e.keyCode === 13) {
                          e.preventDefault()
                          await this._putaway(e)
                        }
                      }}"
                    ></barcode-scanable-input>`
                : html` <label>${i18next.t('label.carton_id')}</label>
                    <barcode-scanable-input
                      name="cartonId"
                      custom-input
                      ?scan-only=${this._pageSettings?.cameraScanOnly}
                      @keypress="${async e => {
                        if (e.keyCode === 13) {
                          e.preventDefault()
                          await this._putaway(e)
                        }
                      }}"
                    ></barcode-scanable-input>`}`
            : html`
                <label>${i18next.t('label.lot_id')}</label>
                <barcode-scanable-input
                  name="palletId"
                  .value=${this._pallet}
                  custom-input
                  ?scan-only=${this._pageSettings?.cameraScanOnly}
                  @keypress="${async e => {
                    if (e.keyCode === 13) {
                      e.preventDefault()
                      await this._putaway(e)
                    }
                  }}"
                ></barcode-scanable-input>
              `}
          ${this._operationType === OPERATION_TYPE.PUTAWAY
            ? html`
                ${!this.incompleteLocationName
                  ? html` <label>${i18next.t('label.location')}</label>
                      <barcode-scanable-input
                        name="locationCode"
                        custom-input
                        ?scan-only=${this._pageSettings?.cameraScanOnly}
                        @keypress="${async e => {
                          if (e.keyCode === 13) {
                            e.preventDefault()
                            await this._putaway(e)
                          }
                        }}"
                      ></barcode-scanable-input>`
                  : ''}
                <select
                  ?hidden="${!this.incompleteLocationName}"
                  name="newLocationCode"
                  @change="${e => (this._selectedLocation = e.currentTarget.value)}"
                >
                  <option value="">-- ${i18next.t('text.please_select_the_location')} --</option>
                  ${(this.locations || []).map(
                    location =>
                      html`
                        <option value="${location && location.name}">
                          ${location && location.name}
                          ${location && location.status ? ` (${location && location.status})` : ''}
                        </option>
                      `
                  )}
                </select>
              `
            : ''}
          ${this.refOrderType === AVAIL_ORDER_TYPES.REPLENISHMENT.value
            ? html`
                <label>${i18next.t('label.actual_qty')}</label>
                <input
                  type="number"
                  min="1"
                  name="actualQty"
                  @keypress="${async e => {
                    if (e.keyCode === 13) {
                      e.preventDefault()
                      await this._putaway(e)
                    }
                  }}"
                />
              `
            : html``}
          ${this._operationType === OPERATION_TYPE.TRANSFER
            ? html` <label>${i18next.t('label.to_lot_barcode')}</label>
                <barcode-scanable-input
                  name="toPalletId"
                  custom-input
                  ?scan-only=${this._pageSettings?.cameraScanOnly}
                  @keypress="${async e => {
                    if (e.keyCode === 13) {
                      e.preventDefault()
                      await this._putaway(e)
                    }
                  }}"
                ></barcode-scanable-input>

                <label>${i18next.t('label.qty')}</label>
                <input
                  type="number"
                  min="1"
                  name="transferQty"
                  @keypress="${async e => {
                    if (e.keyCode === 13) {
                      e.preventDefault()
                      await this._putaway(e)
                    }
                  }}"
                />`
            : html``}
        </fieldset>
      </form>

      <data-grist .mode=${isMobileDevice() ? 'LIST' : 'GRID'} .config=${this.config} .data=${this.data}>
        <div slot="headroom" id="form-section">
          <form id="info-form" class="multi-column-form">
            <fieldset>
              <legend>
                ${this._orderNo}
                ${this._orderNo
                  ? html`(${this._bizplaceName})
                      <mwc-icon @click="${this._openWorksheetInformation.bind(this)}">info</mwc-icon>`
                  : ''}
              </legend>
            </fieldset>
          </form>
        </div>
      </data-grist>
    `
  }

  constructor() {
    super()
    this.data = { records: [] }
    this.refOrderType = AVAIL_ORDER_TYPES.ARRIVAL_NOTICE.value
    this._orderNo = ''
    this._selectedOrderProduct = null
    this._selectedTaskStatus = null
    this.recommendLocationName = null
    this._operationType = OPERATION_TYPE.PUTAWAY
    this._scanning = false
    this.__minInboundShelfLife = 0
    this._expirationDate = 0
    this._locationType = ''
    this._records = []
    this._enableProductScanning = false
  }

  get completed() {
    if (this.data.records.length === 0) {
      return false
    } else {
      return this.data.records.every(record => record.completed)
    }
  }

  updated(changedProps) {
    if (changedProps.has('_selectedTaskStatus') && this._selectedTaskStatus) {
      this.updateContext()
    }

    if (changedProps.has('_operationType')) {
      if (this._enableCartonLabel) this._focusOnCartonInput()
      else this._focusOnPalletInput()
    }
  }

  async pageInitialized() {
    this._pageSettings = {
      ...this._pageSettings,
      cameraScanOnly: (await fetchSettingRule('camera-scan-only')) || false
    }
  }

  pageUpdated() {
    if (this.active) {
      this._focusOnOrderNoField()
      this.config = this.gristConfig
    }
  }

  _focusOnOrderNoField() {
    setTimeout(() => this.orderNoInput.focus(), 100)
  }

  _focusOnPalletInput() {
    setTimeout(() => this.palletInput.focus(), 100)
  }

  _focusOnCartonInput() {
    setTimeout(() => this.cartonInput.focus(), 100)
  }

  _focusOnLocationInput() {
    setTimeout(() => this.locationInput.focus(), 100)
  }

  _focusOnNewLocationInput() {
    setTimeout(() => this.newLocationInput.focus(), 100)
  }

  _focusOnToPalletInput() {
    setTimeout(() => this.toPalletInput.focus(), 100)
  }

  _focusOnQtyInput() {
    setTimeout(() => this.qtyInput.focus(), 100)
  }

  _focusOnProductBarcodeInput() {
    setTimeout(() => this.productBarcodeInput.focus(), 100)
  }

  _focusOnActualQtyInput() {
    setTimeout(() => this.actualQtyInput.focus(), 100)
  }

  _formatConditionOfGoods(conditionValue) {
    if (!conditionValue) return null
    
    const conditionKey = Object.keys(CONDITION_OF_GOODS).find(
      key => CONDITION_OF_GOODS[key].value === conditionValue
    )
    
    if (conditionKey) {
      return i18next.t(`label.${CONDITION_OF_GOODS[conditionKey].name}`)
    }
    
    return conditionValue
  }

  async _fetchProducts(orderNo, preserve = false) {
    if (!preserve) {
      this._clearView()
    }

    if (this.refOrderType === AVAIL_ORDER_TYPES.ARRIVAL_NOTICE.value) {
      const response = await client.query({
        query: gql`
          query putawayWorksheet($arrivalNoticeNo: String!) {
            putawayWorksheet(arrivalNoticeNo: $arrivalNoticeNo) {
              worksheetInfo {
                bizplaceName
                partnerDomainId
                customerCompanyDomainId
                bufferLocation
                refNo
                refNo2
                refNo3
                startedAt
              }
              worksheetDetailInfos {
                name
                palletId
                cartonId
                batchId
                expirationDate
                batchIdRef
                product {
                  sku
                  name
                  description
                  minInboundShelfLife
                  allowStackingOption
                }
                qty
                status
                description
                targetName
                packingType
                packingSize
                location {
                  id
                  name
                  description
                }
                reusablePallet {
                  id
                  name
                }
                conditionOfGoods
                sku
                completed
                packingTypeSize
                reusablePalletName
                expirationPeriod
              }
            }
          }
        `,
        variables: { arrivalNoticeNo: orderNo }
      })

      if (!response.errors) {
        this._orderNo = orderNo
        const worksheetInfo = response.data.putawayWorksheet.worksheetInfo
        const partnerDomainId = worksheetInfo.partnerDomainId
        this._worksheetInfo = worksheetInfo
        this._bizplaceName = worksheetInfo.bizplaceName

        let results = response.data.putawayWorksheet.worksheetDetailInfos
          .map(record => {
            let reusablePalletName = ''
            if (record.reusablePallet) {
              reusablePalletName = record.reusablePallet.name
            }
            return {
              ...record,
              completed: record.status === WORKSHEET_STATUS.DONE.value,
              packingTypeSize: `${record.packingType}(${record.packingSize})`,
              reusablePalletName: reusablePalletName,
              sku: record.product.sku,
              minInboundShelfLife: record.product.minInboundShelfLife,
              expirationDate: record.expirationDate,
              displayConditionOfGoods: this._formatConditionOfGoods(record.conditionOfGoods)
            }
          })
          .sort((a, b) => {
            if (a.completed !== b.completed) {
              if (a.completed) return 1
              if (b.completed) return -1
            }

            if (a.batchId > b.batchId) return 1
            if (b.batchId < b.batchId) return -1

            if (a.palletId > b.palletId) return 1
            if (a.palletId < b.palletId) return -1

            return 0
          })

        this._enableCartonLabel = await fetchSettingRule('enable-carton-label', partnerDomainId)
        this._massageItemList(results)
      }
    } else if (this.refOrderType === AVAIL_ORDER_TYPES.CUSTOMER_RETURN.value) {
      const response = await client.query({
        query: gql`
          query putawayReturningWorksheet($returnOrderNo: String!) {
            putawayReturningWorksheet(returnOrderNo: $returnOrderNo) {
              worksheetInfo {
                bizplaceName
                partnerDomainId
                customerCompanyDomainId
                bufferLocation
                refNo
                refNo
                refNo2
                refNo3
                startedAt
              }
              worksheetDetailInfos {
                name
                palletId
                batchId
                cartonId
                expirationDate
                product {
                  name
                  description
                  sku
                  minInboundShelfLife
                  allowStackingOption
                }
                qty
                status
                description
                targetName
                packingType
                packingSize
                location {
                  id
                  name
                  description
                }
                reusablePallet {
                  id
                  name
                }
                conditionOfGoods
              }
            }
          }
        `,
        variables: { returnOrderNo: orderNo }
      })

      if (!response.errors) {
        this._orderNo = orderNo
        const worksheetInfo = response.data.putawayReturningWorksheet.worksheetInfo
        this._worksheetInfo = worksheetInfo
        this._bizplaceName = worksheetInfo.bizplaceName

        this.data = {
          records: response.data.putawayReturningWorksheet.worksheetDetailInfos
            .map(record => {
              return {
                ...record,
                completed: record.status === WORKSHEET_STATUS.DONE.value,
                sku: record.product.sku,
                minInboundShelfLife: record.product.minInboundShelfLife,
                expirationDate: record.expirationDate,
                location: record.status === WORKSHEET_STATUS.DONE.value ? record.location : null,
                displayConditionOfGoods: this._formatConditionOfGoods(record.conditionOfGoods)
              }
            })
            .sort((a, b) => {
              if (a.completed !== b.completed) {
                if (a.completed) return 1
                if (b.completed) return -1
              }

              if (a.batchId > b.batchId) return 1
              if (b.batchId < b.batchId) return -1

              if (a.palletId > b.palletId) return 1
              if (a.palletId < b.palletId) return -1

              return 0
            })
        }

        this._enableCartonLabel = await fetchSettingRule('enable-carton-label', worksheetInfo.partnerDomainId)
        if (this._enableCartonLabel) this._focusOnCartonInput()
        else this._focusOnPalletInput()
        this._completeHandler()
      }
    } else if (this.refOrderType === AVAIL_ORDER_TYPES.WAREHOUSE_RETURN.value) {
      const response = await client.query({
        query: gql`
          query returnWorksheet($releaseGoodNo: String!) {
            returnWorksheet(releaseGoodNo: $releaseGoodNo) {
              worksheetInfo {
                bizplaceName
                partnerDomainId
                customerCompanyDomainId
                refNo
                refNo2
                refNo3
                startedAt
              }
              worksheetDetailInfos {
                name
                palletId
                cartonId
                batchId
                batchIdRef
                product {
                  name
                  description
                  sku
                }
                qty
                status
                description
                targetName
                packingType
                packingSize
                location {
                  id
                  name
                  description
                }
                conditionOfGoods
              }
            }
          }
        `,
        variables: { releaseGoodNo: orderNo }
      })
      if (!response.errors) {
        this._orderNo = orderNo
        const worksheetInfo = response.data.returnWorksheet.worksheetInfo
        this._worksheetInfo = worksheetInfo
        this._bizplaceName = worksheetInfo.bizplaceName

        this.data = {
          records: response.data.returnWorksheet.worksheetDetailInfos
            .map(record => {
              return {
                ...record,
                sku: record.product.sku,
                completed: record.status === WORKSHEET_STATUS.DONE.value,
                location: record.status === WORKSHEET_STATUS.DONE.value ? record.location : null,
                displayConditionOfGoods: this._formatConditionOfGoods(record.conditionOfGoods)
              }
            })
            .sort((a, b) => {
              if (a.completed !== b.completed) {
                if (a.completed) return 1
                if (b.completed) return -1
              }

              if (a.batchId > b.batchId) return 1
              if (b.batchId < b.batchId) return -1

              if (a.palletId > b.palletId) return 1
              if (a.palletId < b.palletId) return -1

              return 0
            })
        }

        this._enableCartonLabel = await fetchSettingRule('enable-carton-label', worksheetInfo.partnerDomainId)
        if (this._enableCartonLabel) this._focusOnCartonInput()
        else this._focusOnPalletInput()
        this._completeHandler()
      }
    } else if (this.refOrderType === AVAIL_ORDER_TYPES.REPLENISHMENT.value) {
      const response = await client.query({
        query: gql`
          query putawayReplenishmentWorksheet($replenishmentNo: String!) {
            putawayReplenishmentWorksheet(replenishmentNo: $replenishmentNo) {
              worksheetInfo {
                bizplaceName
                status
                partnerDomainId
                replenishment {
                  id
                  name
                }
                customerCompanyDomainId
              }
              worksheetDetailInfos {
                name
                inventory {
                  id
                }
                palletId
                cartonId
                batchId
                expirationDate
                batchIdRef
                product {
                  id
                  sku
                  name
                  description
                  minInboundShelfLife
                  allowStackingOption
                }
                actualPackQty
                qty
                status
                description
                targetName
                packingType
                packingSize
                location {
                  id
                  name
                  description
                }
                conditionOfGoods
              }
            }
          }
        `,
        variables: { replenishmentNo: orderNo }
      })

      if (!response.errors) {
        const worksheetInfo = response.data.putawayReplenishmentWorksheet.worksheetInfo
        this._worksheetInfo = worksheetInfo

        if (worksheetInfo?.replenishment) {
          this._replenishmentId = worksheetInfo.replenishment.id
          this._orderNo = worksheetInfo.replenishment.name
          this._bizplaceName = worksheetInfo.bizplaceName
        } else {
          this._orderNo = orderNo
        }

        this.data = {
          records: response.data.putawayReplenishmentWorksheet.worksheetDetailInfos
            .map(record => {
              let reusablePalletName = ''
              if (record.reusablePallet) {
                reusablePalletName = record.reusablePallet.name
              }
              return {
                ...record,
                inventoryId: record.inventory.id,
                completed: record.status === WORKSHEET_STATUS.DONE.value,
                packingTypeSize: `${record.packingType}(${record.packingSize})`,
                reusablePalletName: reusablePalletName,
                sku: record.product.sku,
                minInboundShelfLife: record.product.minInboundShelfLife,
                expirationDate: record.expirationDate,
                qty: record.actualPackQty + ' / ' + record.qty,
                location: record.status === WORKSHEET_STATUS.DONE.value ? record.location : null,
                displayConditionOfGoods: this._formatConditionOfGoods(record.conditionOfGoods)
              }
            })
            .sort((a, b) => {
              if (a.completed !== b.completed) {
                if (a.completed) return 1
                if (b.completed) return -1
              }

              if (a.batchId > b.batchId) return 1
              if (b.batchId < b.batchId) return -1

              if (a.palletId > b.palletId) return 1
              if (a.palletId < b.palletId) return -1

              return 0
            })
        }

        this._enableCartonLabel = await fetchSettingRule('enable-carton-label', null)
        this._enableProductScanning = await fetchSettingRule('enable-product-scanning', worksheetInfo.partnerDomainId)
        if (this._enableCartonLabel) this._focusOnCartonInput()
        else this._focusOnPalletInput()
        this._completeHandler()
      }
    }
  }

  _clearView() {
    this.data = { records: [] }
    this.infoForm.reset()
    this.inputForm.reset()
    this.orderNoInput.value = ''
    this._selectedOrderProduct = null
    this._selectedTaskStatus = null
    this.recommendLocationName = null
    this.incompleteLocationName = false
    this.updateContext()
  }

  async _transactionHandler(e) {
    if (e.keyCode === 13) {
      if (this.refOrderType === AVAIL_ORDER_TYPES.ARRIVAL_NOTICE.value) {
        if (this._operationType === OPERATION_TYPE.PUTAWAY) {
          await this._arrivalNoticePutaway()
        } else if (this._operationType === OPERATION_TYPE.TRANSFER) {
          await this._transfer()
        }
      } else if (this._operationType === OPERATION_TYPE.PUTAWAY) {
        if (this.refOrderType === AVAIL_ORDER_TYPES.CUSTOMER_RETURN.value) {
          await this._customerReturnPutaway()
        } else if (this.refOrderType === AVAIL_ORDER_TYPES.WAREHOUSE_RETURN.value) {
          await this._warehouseReturnPutaway()
        } else if (this.refOrderType === AVAIL_ORDER_TYPES.REPLENISHMENT.value) {
          await this._replenishmentPutaway()
        }
      }
    }
  }

  async _arrivalNoticePutaway() {
    if (this._scanning === false) {
      this._scanning = true
      this.grist.showSpinner()

      const patches = {
        arrivalNoticeNo: this._orderNo,
        worksheetDetailName: this._selectedOrderProduct?.name || this._selectedOrderProduct.map(itm => itm.name),
        palletId: this._enableCartonLabel ? null : this.getInput(this.palletInput).value,
        cartonId: this._enableCartonLabel ? this.getInput(this.cartonInput).value : null,
        toLocation: this.locationInput ? this.locationInput.value : this._selectedLocation
      }

      try {
        const response = await client.mutate({
          mutation: gql`
            mutation putaway(
              $arrivalNoticeNo: String!
              $worksheetDetailName: [String]!
              $palletId: String
              $cartonId: String
              $toLocation: String!
            ) {
              putaway(
                arrivalNoticeNo: $arrivalNoticeNo
                worksheetDetailName: $worksheetDetailName
                palletId: $palletId
                cartonId: $cartonId
                toLocation: $toLocation
              ) {
                worksheetDetailInfos {
                  name
                  palletId
                  cartonId
                  batchId
                  expirationDate
                  batchIdRef
                  product {
                    sku
                    name
                    description
                    expirationPeriod
                  }
                  qty
                  status
                  description
                  targetName
                  packingType
                  packingSize
                  location {
                    id
                    name
                    description
                  }
                  reusablePallet {
                    id
                    name
                  }
                  conditionOfGoods
                  completed
                  packingTypeSize
                  reusablePalletName
                  sku
                  expirationPeriod
                }
              }
            }
          `,
          variables: patches
        })

        if (!response.errors) {
          this._massageItemList(response.data.putaway.worksheetDetailInfos)
        } else {
          // GraphQL error without throw: clear location input and notify
          if (this.locationInput) {
            this.locationInput.value = ''
          } else {
            this._selectedLocation = ''
          }
          const msg = response.errors?.[0]?.message || i18next.t('text.something_went_wrong')
          this._showToast({ message: msg })
        }
      } catch (e) {
        this._showToast(e)
      }

      this.grist.hideSpinner()
      this._scanning = false
    } else {
      this._showToast({ message: i18next.t('text.previous_scan_is_executing') })
    }
  }

  async _customerReturnPutaway() {
    if (this._scanning === false) {
      this._scanning = true
      try {
        const locationDetails = await this._fetchLocation(
          this.locationInput ? this.locationInput.value.trim() : this._selectedLocation.trim()
        )

        let worksheetDetailNames = await this._getWorksheetDetailNames(locationDetails)

        if (!worksheetDetailNames) {
          return (this._scanning = false)
        }

        const response = await client.mutate({
          mutation: gql`
            mutation putawayReturn(
              $worksheetDetailName: [String]!
              $palletId: String
              $cartonId: String
              $toLocation: String!
            ) {
              putawayReturn(
                worksheetDetailName: $worksheetDetailName
                palletId: $palletId
                cartonId: $cartonId
                toLocation: $toLocation
              )
            }
          `,
          variables: {
            worksheetDetailName: worksheetDetailNames,
            palletId: this._enableCartonLabel ? null : this.getInput(this.palletInput).value,
            cartonId: this._enableCartonLabel ? this.getInput(this.cartonInput).value : null,
            toLocation: this.locationInput ? this.locationInput.value : this._selectedLocation
          }
        })

        if (!response.errors) {
          this._fetchProducts(this._orderNo)
          if (this._enableCartonLabel) {
            this.getInput(this.cartonInput).value = ''
            this._focusOnCartonInput()
          } else {
            this.getInput(this.palletInput).value = ''
            this._focusOnPalletInput()
          }
          this.incompleteLocationName = false
          this._selectedTaskStatus = null
          this._selectedOrderProduct = null
          this.recommendLocationName = null
          if (this.locationInput) {
            this.locationInput.value = ''
          } else {
            this._selectedLocation = ''
          }
        } else {
          if (this.locationInput) {
            this.locationInput.value = ''
          } else {
            this._selectedLocation = ''
          }
          const msg = response.errors?.[0]?.message || i18next.t('text.something_went_wrong')
          this._showToast({ message: msg })
        }
      } catch (e) {
        this._showToast(e)
      }

      this._scanning = false
    } else {
      this._showToast({ message: i18next.t('text.previous_scan_is_executing') })
    }
  }

  _openWorksheetInformation() {
    openPopup(
      html`
        <worksheet-information-popup .worksheetInformation="${this._worksheetInfo}"></worksheet-information-popup>
      `,
      {
        backdrop: true,
        size: 'large',
        title: i18next.t('title.order_information')
      }
    )
  }

  async _warehouseReturnPutaway() {
    if (this._scanning === false) {
      this._scanning = true
      try {
        let worksheetDetailNames = await this._getWorksheetDetailNames()

        const response = await client.mutate({
          mutation: gql`
            mutation returning(
              $worksheetDetailName: [String]!
              $palletId: String
              $cartonId: String
              $toLocation: String!
            ) {
              returning(
                worksheetDetailName: $worksheetDetailName
                palletId: $palletId
                cartonId: $cartonId
                toLocation: $toLocation
              )
            }
          `,
          variables: {
            worksheetDetailName: worksheetDetailNames,
            palletId: this._enableCartonLabel ? null : this.getInput(this.palletInput).value,
            cartonId: this._enableCartonLabel ? this.getInput(this.cartonInput).value : null,
            toLocation: this.locationInput ? this.locationInput.value : this._selectedLocation
          }
        })

        if (!response.errors) {
          this._fetchProducts(this._orderNo)
          if (this._enableCartonLabel) {
            this.getInput(this.cartonInput).value = ''
            this._focusOnCartonInput()
          } else {
            this.getInput(this.palletInput).value = ''
            this._focusOnPalletInput()
          }

          this._selectedTaskStatus = null
          this._selectedOrderProduct = null
          this.recommendLocationName = null
          this.locationInput.value = ''
        } else {
          if (this.locationInput) {
            this.locationInput.value = ''
          } else {
            this._selectedLocation = ''
          }
          const msg = response.errors?.[0]?.message || i18next.t('text.something_went_wrong')
          this._showToast({ message: msg })
        }
      } catch (e) {
        this._showToast(e)
      }

      this._scanning = false
    } else {
      this._showToast({ message: i18next.t('text.previous_scan_is_executing') })
    }
  }

  async _replenishmentPutaway() {
    if (this._scanning === false) {
      this._scanning = true
      try {
        let worksheetDetailNames = []
        const locationDetails = await this._fetchLocation(
          this.locationInput ? this.locationInput.value.trim() : this._selectedLocation.trim()
        )

        if (this._enableCartonLabel && this._enableProductScanning) {
          this._records.forEach(record => {
            worksheetDetailNames.push(record.name)
          })
        } else {
          worksheetDetailNames = await this._getWorksheetDetailNames(locationDetails)
        }

        if (!worksheetDetailNames) {
          return (this._scanning = false)
        }

        let productBarcode
        let cartonId
        if (this._enableCartonLabel && this._enableProductScanning) {
          productBarcode = this.getInput(this.productBarcodeInput)?.value
          cartonId = this.locationInput.value
        } else {
          productBarcode = null
          cartonId = this.getInput(this.cartonInput).value
        }

        const response = await client.mutate({
          mutation: gql`
            mutation replenishmentPutaway(
              $worksheetDetailName: [String]!
              $cartonId: String
              $toLocation: String!
              $actualQty: Int!
              $productBarcode: String
            ) {
              replenishmentPutaway(
                worksheetDetailName: $worksheetDetailName
                cartonId: $cartonId
                toLocation: $toLocation
                actualQty: $actualQty
                productBarcode: $productBarcode
              )
            }
          `,
          variables: {
            worksheetDetailName: worksheetDetailNames,
            cartonId: cartonId,
            toLocation: this.locationInput ? this.locationInput.value : this._selectedLocation,
            actualQty: this.actualQtyInput ? parseInt(this.actualQtyInput.value) : null,
            productBarcode: productBarcode
          }
        })

        if (!response.errors) {
          this._fetchProducts(this._orderNo)
          if (this._enableCartonLabel && !this._enableProductScanning) {
            this.getInput(this.cartonInput).value = ''
            this._focusOnCartonInput()
          } else if (this._enableCartonLabel && this._enableProductScanning) {
            this.getInput(this.productBarcodeInput).value = ''
            this._focusOnProductBarcodeInput()
          } else {
            this.getInput(this.palletInput).value = ''
            this._focusOnPalletInput()
          }
          this.incompleteLocationName = false
          this._selectedTaskStatus = null
          this._selectedOrderProduct = null
          this.recommendLocationName = null
          this._records = []
          if (this.locationInput) {
            this.locationInput.value = ''
          } else {
            this._selectedLocation = ''
          }
        } else {
          if (this.locationInput) {
            this.locationInput.value = ''
          } else {
            this._selectedLocation = ''
          }
          const msg = response.errors?.[0]?.message || i18next.t('text.something_went_wrong')
          this._showToast({ message: msg })
        }
      } catch (e) {
        this._showToast(e)
      }

      this._scanning = false
    } else {
      this._showToast({ message: i18next.t('text.previous_scan_is_executing') })
    }
  }

  _openReplenishmentPutawayInventoriesPopup(replenishmentId, inventoryId) {
    openPopup(
      html`
        <putaway-replenishment-inventory-popup .replenishmentId="${replenishmentId}" .inventoryId="${inventoryId}">
        </putaway-replenishment-inventory-popup>
      `,
      {
        backdrop: true,
        size: 'large',
        title: `${i18next.t('title.putaway_inventories')}`
      }
    )
  }

  async _transfer() {
    try {
      this._validateTransfer()
      const response = await client.mutate({
        mutation: gql`
          mutation transfer($palletId: String!, $toPalletId: String!, $qty: Int!) {
            transfer(palletId: $palletId, toPalletId: $toPalletId, qty: $qty)
          }
        `,
        variables: {
          palletId: this.getInput(this.palletInput).value,
          toPalletId: this.toPalletInput.value,
          qty: parseInt(this.qtyInput.value)
        }
      })

      if (!response.errors) {
        this._fetchProducts(this._orderNo)
        this._focusOnPalletInput()
        this._selectedTaskStatus = null
        this._selectedOrderProduct = null
        this.recommendLocationName = null
        this.getInput(this.palletInput).value = ''
        this.toPalletInput.value = ''
        this.qtyInput.value = ''
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  async _expiryAlert(expiringProducts) {
    const answer = await CustomAlert({
      title: i18next.t('title.location_scanned_is_not_a_quarantine_zone'),
      text: i18next.t('text.x_is_expiring', { x: expiringProducts }),
      confirmButton: { text: i18next.t('button.confirm') },
      cancelButton: { text: i18next.t('button.cancel') }
    })

    return answer
  }

  async _getWorksheetDetailNames(locationDetails) {
    let worksheetDetailNames = []
    if (this._enableCartonLabel) {
      this._records
        .filter(record => record.cartonId === this.getInput(this.cartonInput).value && record.status !== 'DONE')
        .forEach(itm => {
          worksheetDetailNames.push(itm.name)
        })
      if (this._records.find(itm => itm.expirationDate) && locationDetails) {
        let answer = await this._checkExpiry(this._records, locationDetails.type)
        if (answer) {
          if (!answer?.value) return false
        }
      }
    } else {
      worksheetDetailNames.push(this._selectedOrderProduct.name)
      if (this._selectedOrderProduct.expirationDate && locationDetails) {
        let answer = await this._checkExpiry([this._selectedOrderProduct], locationDetails.type)
        if (answer) {
          if (!answer?.value) return false
        }
      }
    }
    return worksheetDetailNames
  }

  async _putaway(e) {
    if (e.keyCode === 13) {
      try {
        let records = []
        await this._validatePutaway()
        if (this._enableCartonLabel && this.refOrderType !== AVAIL_ORDER_TYPES.REPLENISHMENT.value) {
          records = this.data.records
            .filter(record => record.cartonId === this.getInput(this.cartonInput).value && record.status !== 'DONE')
            .map(record => {
              return {
                name: record.name,
                expirationDate: record.expirationDate,
                minInboundShelfLife: record.product.minInboundShelfLife,
                palletId: record.palletId,
                cartonId: record.cartonId
              }
            })
        } else if (this.refOrderType === AVAIL_ORDER_TYPES.REPLENISHMENT.value) {
          if (this._enableProductScanning) {
            await this._checkedScannedProduct(e)
            return
          } else {
            records = this.data.records
              .filter(record => record.cartonId === this.getInput(this.cartonInput).value && record.status !== 'DONE')
              .map(record => {
                return {
                  name: record.name,
                  expirationDate: record.expirationDate,
                  minInboundShelfLife: record.product.minInboundShelfLife,
                  palletId: record.palletId,
                  cartonId: record.cartonId
                }
              })
          }
        }
        if (records.length > 1) {
          this._openPutawaySameCartonPopup(this.getInput(this.cartonInput).value)
        } else {
          this._records = this.data.records
          this._transactionHandler(e)
        }
      } catch (e) {
        this._showToast(e)
      }
    }
  }

  _openPutawaySameCartonPopup(scannedCartonId) {
    openPopup(
      html`
        <putaway-same-carton-popup
          .putawayInventories="${this.data.records.filter(
            record => record.cartonId === scannedCartonId && record.completed === false
          )}"
          @selections="${e => {
            this._selectedOrderProduct = e.detail
            this._records = e.detail
            e.keyCode = 13
            this._transactionHandler(e)
          }}"
        ></putaway-same-carton-popup>
      `,
      {
        backdrop: true,
        size: 'medium',
        title: i18next.t('title.select_product_batch')
      }
    )
  }

  _openPutawaySameProductPopup(orderProduct) {
    openPopup(
      html`
        <putaway-replenishment-same-product-popup
          .putawayInventories="${this.data.records.filter(
            record => orderProduct.some(op => op.sku === record.sku) && record.completed === false
          )}"
          @selections="${async e => {
            this._selectedOrderProduct = e.detail
            this._records = e.detail

            if (this._records.expirationDate && locationDetails) {
              let answer = await this._checkExpiry([this._records], locationDetails.type)
              if (answer) {
                if (!answer?.value) return false
              }
            }

            e.keyCode = 13
            this._transactionHandler(e)
          }}"
        ></putaway-replenishment-same-product-popup>
      `,
      {
        backdrop: true,
        size: 'medium',
        title: i18next.t('title.select_product_batch')
      }
    )
  }
  async _validatePutaway() {
    if (this._enableCartonLabel && this.refOrderType !== AVAIL_ORDER_TYPES.REPLENISHMENT.value) {
      let cartonInputValue = this.getInput(this.cartonInput).value

      // 2. carton id existing
      if (!cartonInputValue) {
        this._focusOnCartonInput()
        throw new Error(i18next.t('text.carton_id_is_empty'))
      }

      if (!this.data.records.map(record => record.cartonId).includes(cartonInputValue)) {
        this.getInput(this.cartonInput).value = ''
        this._focusOnCartonInput()
        throw new Error(i18next.t('text.unable_to_find_matching_x', { state: { x: i18next.t('label.carton') } }))
      } else {
        this._selectedOrderProduct = [
          this.data.records.find(x => x.cartonId == cartonInputValue && x.status !== 'DONE')
        ]
      }
    } else if (this._enableCartonLabel && this.refOrderType === AVAIL_ORDER_TYPES.REPLENISHMENT.value) {
      //validate input for replenishment with carton
      if (this._enableProductScanning) {
        if (!this.getInput(this.productBarcodeInput).value) {
          this._focusOnProductBarcodeInput()
          throw new Error(i18next.t('text.product_barcode_is_empty'))
        }
      } else {
        let cartonInputValue = this.getInput(this.cartonInput).value
        if (!cartonInputValue) {
          this._focusOnCartonInput()
          throw new Error(i18next.t('text.carton_id_is_empty'))
        }

        if (!this.data.records.map(record => record.cartonId).includes(cartonInputValue)) {
          this.getInput(this.cartonInput).value = ''
          this._focusOnCartonInput()
          throw new Error(i18next.t('text.unable_to_find_matching_x', { state: { x: i18next.t('label.carton') } }))
        } else {
          this._selectedOrderProduct = [
            this.data.records.find(x => x.cartonId == cartonInputValue && x.status !== 'DONE')
          ]
        }
      }

      if (!this.actualQtyInput || isNaN(parseFloat(this.actualQtyInput.value))) {
        this._focusOnActualQtyInput()
        throw new Error(i18next.t('text.actual_qty_is_invalid'))
      }
    } else {
      let palletInputValue = this.getInput(this.palletInput).value

      // 2. pallet id existing
      if (!palletInputValue) {
        this._focusOnPalletInput()
        throw new Error(i18next.t('text.lot_id_is_empty'))
      }

      if (!this._selectedOrderProduct?.palletId !== palletInputValue) {
        this._selectedOrderProduct = this.data.records.find(x => x.palletId == palletInputValue && x.status !== 'DONE')

        if (!this._selectedOrderProduct)
          throw new Error(i18next.t('text.unable_to_find_matching_x', { state: { x: i18next.t('label.lot_id') } }))
      }

      if (!this._selectedOrderProduct) throw new Error(i18next.t('text.target_is_not_selected'))

      // 3. equality of pallet id
      if (this._selectedOrderProduct.reusablePalletName !== this.getInput(this.palletInput).value) {
        if (this._selectedOrderProduct.palletId !== this.getInput(this.palletInput).value) {
          setTimeout(() => this.palletInput.select(), 100)
          throw new Error(i18next.t('text.wrong_lot_id'))
        }
      }
    }

    // 4. location code existing
    if (!this.locationInput?.value && !this._selectedLocation) {
      this._focusOnLocationInput()
      throw new Error(i18next.t('text.location_code_is_empty'))
    } else if (this.locationInput?.value && !this._selectedLocation) {
      const foundLocation = await this._fetchLocation(this.locationInput.value.trim())
      if (!foundLocation) {
        const locationNameSplit = this.locationInput.value.split('-')
        if (locationNameSplit.length !== 3) throw new Error(i18next.t('text.invalid_format_of_location_id'))
        this._focusOnNewLocationInput()
        const zonePortions = locationNameSplit[0].match(/[a-zA-Z0-9]+/g)
        const rowPortions = locationNameSplit[1].match(/[a-zA-Z0-9]+/g)
        const columnPortions = locationNameSplit[2].match(/[a-zA-Z0-9]+/g)

        this.incompleteLocationName = true
        this.locations = await this._fetchLocations(zonePortions[0], rowPortions[0], columnPortions[0])
        if (this.locations.length > 0) {
          this.incompleteLocationName = true
          throw new Error(i18next.t('text.please_select_the_location_again'))
        } else {
          throw new Error(i18next.t('text.invalid_return_location'))
        }
      } else {
        this.incompleteLocationName = false
      }
    }
  }

  async _checkExpiry(worksheetDetails, locationType) {
    let expiringProducts = []
    for (let wsd of worksheetDetails) {
      new Date(wsd.expirationDate)
      let date = new Date()
      let acceptBefore = new Date(date.setDate(date.getDate() + wsd.minInboundShelfLife))

      if (wsd.minInboundShelfLife > 0 && wsd.expirationDate) {
        if (new Date(wsd.expirationDate) < acceptBefore && locationType !== 'QUARANTINE') {
          expiringProducts.push(wsd.palletId)
        }
      }
    }
    if (expiringProducts.length > 0) {
      return this._expiryAlert(expiringProducts.toString())
    }
  }

  _validateTransfer() {
    // 1. validate for order selection
    if (!this._selectedOrderProduct) throw new Error(i18next.t('text.target_is_not_selected'))

    // 2. pallet id existing
    if (!this.getInput(this.palletInput).value) {
      this._focusOnPalletInput()
      throw new Error(i18next.t('text.lot_id_is_empty'))
    }

    // 3. Equality of pallet id
    if (this._selectedOrderProduct.palletId !== this.getInput(this.palletInput).value) {
      setTimeout(() => this.palletInput.select(), 100)
      throw new Error(i18next.t('text.wrong_lot_id'))
    }

    // 4. to pallet id existing
    if (!this.toPalletInput.value) {
      this._focusOnToPalletInput()
      throw new Error(i18next.t('text.to_lot_id_is_empty'))
    }

    // 5. qty existing
    if (!this.qtyInput.value) {
      this._focusOnQtyInput()
      throw new Error(i18next.t('text.qty_is_empty'))
    }

    if (parseInt(this.qtyInput.value) > this._selectedOrderProduct.qty) {
      this._focusOnQtyInput()
      throw new Error(i18next.t('text.qty_exceed_limit'))
    }
  }

  async _fetchLocations(zone, row, column) {
    const filters = [
      {
        name: 'zone',
        operator: 'eq',
        value: zone
      },
      {
        name: 'row',
        operator: 'eq',
        value: row
      },
      {
        name: 'column',
        operator: 'eq',
        value: column
      }
    ]

    if (filters) {
      const response = await client.query({
        query: gql`
          query locations($filters: [Filter!]!) {
            locations(filters: $filters) {
              items {
                id
                name
                zone
                row
                column
                shelf
                status
              }
            }
          }
        `,
        variables: { filters }
      })

      if (!response.errors) {
        return response.data.locations.items || []
      }
    }
  }

  async _fetchLocation(locationName) {
    if (locationName) {
      const response = await client.query({
        query: gql`
          query location($name: String!) {
            location(name: $name) {
              id
              name
              zone
              row
              column
              shelf
              type
            }
          }
        `,
        variables: { name: locationName }
      })

      if (!response.errors) {
        return response.data.location
      }
    }
  }

  _openSelectLocationPopup() {
    openPopup(
      html`
        <select-location-popup
          .locations="${this.locations}"
          @location-selected="${e => {
            this.locationInput.value = e.detail.location.name
            this.incompleteLocationName = false
            this._transactionHandler(e.detail)
          }}"
        ></select-location-popup>
      `,
      {
        backdrop: true,
        size: 'medium',
        title: i18next.t('title.select_location')
      }
    )
  }

  async _openUndoPopup() {
    await sleep(1010)
    openPopup(
      html`
        <undo-putaway-popup
          .enableCartonLabel="${this._enableCartonLabel}"
          .enableProductScanning="${this._enableProductScanning}"
          .replenishmentId="${this.refOrderType === AVAIL_ORDER_TYPES.REPLENISHMENT.value
            ? this._replenishmentId
            : null}"
          .orderType="${this.refOrderType}"
          .orderNo="${this._orderNo}"
          .putawayInventories="${this.data.records.filter(itm => itm.status == 'DONE')}"
          @undo-inventory="${async e => {
            history.back()
            await this._fetchProducts(this._orderNo)
            if (this._enableCartonLabel) {
              this.getInput(this.cartonInput).value = ''
              this._focusOnCartonInput()
            } else {
              this.getInput(this.palletInput).value = ''
              this._focusOnPalletInput()
            }
            this._selectedTaskStatus = null
            this._selectedOrderProduct = null
            this.recommendLocationName = null
            if (this.locationInput) {
              this.locationInput.value = ''
            } else {
              this._selectedLocation = ''
            }
            this._showToast({ message: i18next.t('text.inventory_undo_successfully') })
          }}"
        ></undo-putaway-popup>
      `,
      {
        backdrop: true,
        size: 'large',
        title: i18next.t('title.undo_putaway')
      }
    )
  }

  async _completeHandler() {
    if (!this.data.records.every(record => record.completed)) return
    this.updateContext()
    const result = await CustomAlert({
      title: i18next.t('title.putaway'),
      text: i18next.t('text.do_you_want_to_complete'),
      confirmButton: { text: i18next.t('button.confirm') },
      cancelButton: { text: i18next.t('button.cancel') }
    })

    if (result.value)
      if (this.refOrderType === AVAIL_ORDER_TYPES.ARRIVAL_NOTICE.value) {
        this._completeArrivalNoticePutaway()
      } else if (this.refOrderType === AVAIL_ORDER_TYPES.CUSTOMER_RETURN.value) {
        this._completeCustomerReturnPutaway()
      } else if (this.refOrderType === AVAIL_ORDER_TYPES.WAREHOUSE_RETURN.value) {
        this._completeWarehouseReturnPutaway()
      } else if (this.refOrderType === AVAIL_ORDER_TYPES.REPLENISHMENT.value) {
        this._completeReplenishmentPutaway()
      }
  }

  async _completeArrivalNoticePutaway() {
    const response = await client.mutate({
      mutation: gql`
        mutation completePutaway($arrivalNoticeNo: String!) {
          completePutaway(arrivalNoticeNo: $arrivalNoticeNo)
        }
      `,
      variables: { arrivalNoticeNo: this._orderNo }
    })

    if (!response.errors) {
      this._clearView()
      this._orderNo = ''
      await CustomAlert({
        title: i18next.t('title.completed'),
        text: i18next.t('text.putaway_completed'),
        confirmButton: { text: i18next.t('button.confirm') }
      })
    }
  }

  async _completeCustomerReturnPutaway() {
    const response = await client.mutate({
      mutation: gql`
        mutation completePutawayReturn($returnOrderNo: String!) {
          completePutawayReturn(returnOrderNo: $returnOrderNo)
        }
      `,
      variables: { returnOrderNo: this._orderNo }
    })

    if (!response.errors) {
      this._clearView()
      this._orderNo = ''
      await CustomAlert({
        title: i18next.t('title.completed'),
        text: i18next.t('text.putaway_completed'),
        confirmButton: { text: i18next.t('button.confirm') }
      })
    }
  }

  async _completeWarehouseReturnPutaway() {
    const response = await client.mutate({
      mutation: gql`
        mutation completeReturn($releaseGoodNo: String!) {
          completeReturn(releaseGoodNo: $releaseGoodNo)
        }
      `,
      variables: { releaseGoodNo: this._orderNo }
    })

    if (!response.errors) {
      this._clearView()
      this._orderNo = ''
      await CustomAlert({
        title: i18next.t('title.completed'),
        text: i18next.t('text.putaway_completed'),
        confirmButton: { text: i18next.t('button.confirm') }
      })
    }
  }

  async _completeReplenishmentPutaway() {
    const response = await client.mutate({
      mutation: gql`
        mutation completeReplenishmentPutaway($replenishmentNo: String!) {
          completeReplenishmentPutaway(replenishmentNo: $replenishmentNo)
        }
      `,
      variables: { replenishmentNo: this._orderNo }
    })

    if (!response.errors) {
      this._clearView()
      this._orderNo = ''
      await CustomAlert({
        title: i18next.t('title.completed'),
        text: i18next.t('text.putaway_replenishment_completed'),
        confirmButton: { text: i18next.t('button.confirm') }
      })
    }
  }

  orderTypeChangeHandler(e) {
    this.refOrderType = e.currentTarget.value
    this._clearView()
    this.config = this.gristConfig
    this.orderNoInput.select()
  }

  async _getLocationRecommendation(worksheetDetailName) {
    const response = await client.query({
      query: gql`
        query recommendPutawayLocation($worksheetDetailName: String!, $optCnt: Int) {
          recommendPutawayLocation(worksheetDetailName: $worksheetDetailName, optCnt: $optCnt) {
            name
          }
        }
      `,
      variables: { worksheetDetailName, optCnt: 1 }
    })

    if (!response.errors) {
      return response.data.recommendPutawayLocation[0]?.name || ''
    }
  }

  async _checkedScannedProduct(e) {
    const response = await this.fetchProductDetails(this.getInput(this.productBarcodeInput).value.trim() || '')
    const locationDetails = await this._fetchLocation(
      this.locationInput ? this.locationInput.value.trim() : this._selectedLocation.trim()
    )

    if (!response.errors) {
      let orderProductData = this.data.records.filter(record => record.completed === false)
      let checkedProductDetails = response.data.checkGtin.items

      const foundOrderProducts = orderProductData.filter(op => {
        return checkedProductDetails.some(
          itm =>
            itm.product.id == op.product.id && itm.packingType == op.packingType && itm.packingSize == op.packingSize
        )
      })

      const foundParentProducts = orderProductData.filter(op => {
        return checkedProductDetails.some(itm => itm.product.id == op.product.id)
      })

      if (foundOrderProducts?.length > 1) {
        this._openPutawaySameProductPopup(foundOrderProducts)
        return
      } else if (foundOrderProducts?.length == 1) {
        this._records.push(foundOrderProducts[0])
      } else if (foundOrderProducts?.length == 0 && foundParentProducts?.length > 0) {
        this._records.push(foundParentProducts[0])
      }

      if (this._records.some(record => record.expirationDate) && locationDetails) {
        let answer = await this._checkExpiry([this._records], locationDetails.type)
        if (answer) {
          if (!answer?.value) return false
        }
      }
      this._transactionHandler(e)
    } else {
      return this._showToast({ message: i18next.t('text.no_matching_product_found') })
    }
  }

  async fetchProductDetails(gtin) {
    return await client.query({
      query: gql`
        query checkGtin($gtin: String!, $customerCompanyDomainId: String!) {
          checkGtin(gtin: $gtin, customerCompanyDomainId: $customerCompanyDomainId) {
            items {
              id
              name
              packingType
              packingSize
              gtin
              product {
                id
                name
                sku
              }
            }
            total
          }
        }
      `,
      variables: {
        gtin,
        customerCompanyDomainId: this._worksheetInfo.customerCompanyDomainId
      }
    })
  }

  _massageItemList(worksheetDetailInfos) {
    if (this._enableCartonLabel) {
      if (this.cartonInput) this.getInput(this.cartonInput).value = ''
      this._focusOnCartonInput()
    } else {
      if (this.palletInput) this.getInput(this.palletInput).value = ''
      this._focusOnPalletInput()
    }

    this.incompleteLocationName = false
    this._selectedTaskStatus = null
    this._selectedOrderProduct = null
    this.recommendLocationName = null

    if (this.locationInput) {
      this.locationInput.value = ''
    } else {
      this._selectedLocation = ''
    }

    this.data = {
      records: worksheetDetailInfos.map(itm => {
        return {
          ...itm,
          location: itm.status === WORKSHEET_STATUS.DONE.value ? itm.location : null,
          displayConditionOfGoods: this._formatConditionOfGoods(itm.conditionOfGoods)
        }
      })
    }

    this._completeHandler()
  }

  _showToast({ type, message }) {
    document.dispatchEvent(
      new CustomEvent('notify', {
        detail: {
          type,
          message
        }
      })
    )
  }
}

window.customElements.define('putaway-product', PutawayProduct)
