import '@things-factory/barcode-ui'
import '@things-factory/grist-ui'
import '../components/worksheet-information-popup'
import './serial-number-popup'
import './order-remark-popup'
import './packing-serial-number-popup'

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

import { GhostPrint } from '@operato/ghost-print'
import { sleep } from '@operato/utils'
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 } from '@things-factory/utils'

import { fetchSettingRule } from '../../fetch-setting-value'
import { decodeQR, fetchPageSettings, isValidHttpUrl } from '../../util/index'
import { ORDER_SOURCES, PLATFORM, WORKSHEET_STATUS } from '../constants'

class PackingProduct extends connect(store)(localize(i18next)(PageView)) {
  static get properties() {
    return {
      airwayBill: String,
      checkedRemarkAt: String,
      config: Object,
      data: Object,
      invoice: String,
      orderInformation: String,
      orderRemark: String,
      platform: String,
      releaseGoodNo: String,
      releaseGoodId: String,
      shippingProvider: String,
      trackingNo: String,
      totalBinRO: Number,
      binRo: String,
      ownTransport: Boolean,
      toggleComplete: Boolean,
      lmdOption: Boolean,
      _bizplaceName: String,
      _enableProductScanning: Boolean,
      _qrProcessing: Number,
      _productName: String,
      _logisticsInitiated: Boolean,
      _selectedTaskStatus: String,
      _worksheetInfo: Object,
      _orderPackageInformation: Object,
      _scanning: Boolean,
      _isRequireSerialNumberScanningOutbound: Boolean,
      _isBatchPicking: Boolean,
      _isLmdOption: Boolean,
      _awbAttempts: Number,
      grossWeight: Number,
      _enablePackingGrossWeight: Boolean
    }
  }

  static get styles() {
    return [
      MultiColumnFormStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow: hidden;
        }
        data-grist {
          overflow: auto;
          flex: 1;
        }
        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 completed() {
    return this.orderRemark
      ? this.data.records.every(record => record.completed) && Boolean(this.checkedRemarkAt)
      : this.data.records.every(record => record.completed)
  }

  get context() {
    var actions = []

    if (this.releaseGoodNo && !this._isLmdOption) {
      actions.push({
        title: i18next.t('button.packing_list'),
        action: this.packingList.bind(this),
        ...CommonButtonStyles.label
      })
    }

    if (
      this.releaseGoodNo &&
      (this.platform === PLATFORM.LAZADA.value || this.platform === PLATFORM.SHOPEE.value) &&
      this.completed &&
      this.trackingNo
    ) {
      actions.push({
        title: i18next.t('button.print_airway_bill'),
        action: this.printAirwayBill.bind(this),
        ...CommonButtonStyles.label
      })

      actions.push({
        title: i18next.t('button.print_invoice'),
        action: this.printInvoice.bind(this),
        ...CommonButtonStyles.label
      })
    }

    if (this.releaseGoodNo && this.source == 'SELLERCRAFT' && this.platform == 'operato' && this.completed) {
      actions.push({
        title: i18next.t('button.print_airway_bill'),
        action: this.printSellercraftDocument.bind(this, 'awb'),
        ...CommonButtonStyles.label
      })

      actions.push({
        title: i18next.t('button.print_invoice'),
        action: this.printSellercraftDocument.bind(this, 'invoice'),
        ...CommonButtonStyles.label
      })
    }

    if (this.releaseGoodNo && this.platform == 'operato' && this.completed) {
      switch (this.source) {
        case 'POWRUP':
          actions.push({
            title: i18next.t('button.print_airway_bill'),
            action: this.printPowrupDocument.bind(this, 'awb'),
            ...CommonButtonStyles.label
          })

          actions.push({
            title: i18next.t('button.print_invoice'),
            action: this.printPowrupDocument.bind(this, 'invoice'),
            ...CommonButtonStyles.label
          })

          break

        case 'WEBSPERT':
          actions.push({
            title: i18next.t('button.print_airway_bill'),
            action: this.printWebspertDocument.bind(this, 'awb'),
            ...CommonButtonStyles.label
          })

          break
      }
    }

    if (
      this.releaseGoodNo &&
      (this.orderInformation?.status === 'packed' ||
        this.orderInformation?.status === 'unfulfilled' ||
        this.orderInformation?.status === 'processing') &&
      !this._trackingNo &&
      !this._logisticsInitiated &&
      (this.platform === PLATFORM.LAZADA.value ||
        this.platform === PLATFORM.SHOPIFY.value ||
        this.platform === PLATFORM.WOOCOMMERCE.value) &&
      this.completed
    ) {
      actions.push({
        title: i18next.t('button.ready_to_ship'),
        action: this.setOrderToRTS.bind(this),
        ...CommonButtonStyles.logistics
      })
    }

    if (this._isRequireSerialNumberScanningOutbound && this._isBatchPicking) {
      actions.push({
        title: i18next.t('button.serial_number'),
        action: this.openSerialNumberPopup.bind(this),
        ...CommonButtonStyles.activate
      })
    }

    if (
      this.releaseGoodNo &&
      (this.source == 'OTHERS' || this.source == null) &&
      this.platform == 'operato' &&
      this.completed
    ) {
      actions.push({
        title: i18next.t('button.print_airway_bill'),
        action: this.printB2cDocument.bind(this, 'awb'),
        ...CommonButtonStyles.label
      })

      if (this.invoice) {
        actions.push({
          title: i18next.t('button.print_invoice'),
          action: this.printB2cDocument.bind(this, 'invoice'),
          ...CommonButtonStyles.label
        })
      }
    }

    if (this.orderRemark) {
      actions.push({
        title: i18next.t('button.order_remark'),
        action: this.openOrderRemarkPopup.bind(this),
        ...CommonButtonStyles.inspect
      })
    }

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

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

  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=locationName]').shadowRoot.querySelector('input')
  }

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

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

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

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

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

  get scannable() {
    return this._selectedTaskStatus && this._selectedTaskStatus === WORKSHEET_STATUS.EXECUTING.value
  }

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

  focusOnReleaseGoodInput() {
    setTimeout(() => this.releaseGoodNoInput.focus(), 100)
  }

  focusOnReleaseQtyInput() {
    setTimeout(() => this.releaseQtyInput.focus(), 100)
  }

  focusOnSerialInput() {
    if (this.serialInput) {
      setTimeout(() => this.serialInput.focus(), 50)
    }
  }

  addGrossWeightListener() {
    const grossWeightInput = this.shadowRoot.querySelector('#grossWeightInput')
    if (grossWeightInput) {
      grossWeightInput.addEventListener('input', event => {
        let value = event.target.value

        // Check if the input is valid and contains more than 3 decimal places
        if (value.includes('.')) {
          let [integer, decimals] = value.split('.')
          if (decimals.length > 3) {
            event.target.value = `${integer}.${decimals.slice(0, 3)}`
          }
        }
      })
    } else {
      console.error('Gross weight input not found.')
    }
  }

  render() {
    return html`
      <form id="info-form" class="multi-column-form" style="align-items:center">
        <fieldset>
          <label>${i18next.t('label.release_good_no')}</label>
          <barcode-scanable-input
            name="releaseGoodNo"
            custom-input
            @keypress="${async e => {
              if (e.keyCode === 13) {
                e.preventDefault()
                if (this.releaseGoodNoInput.value) {
                  this.fetchInventories(this.releaseGoodNoInput.value)
                  this.releaseGoodNoInput.value = ''
                }
              }
            }}"
          ></barcode-scanable-input>
        </fieldset>
      </form>

      <form id="input-form" class="multi-column-form" @keypress="${this.packing.bind(this)}">
        <fieldset>
          ${this._enableProductScanning
            ? html`
                <label>${i18next.t('label.product_barcode')}</label>
                <barcode-scanable-input
                  name="productBarcode"
                  custom-input
                  @keypress="${async e => {
                    if (e.keyCode === 13) {
                      e.preventDefault()
                      await this._processQRAndFillForm(e)
                    }
                  }}"
                ></barcode-scanable-input>

                ${this._enablePackingGrossWeight
                  ? html` <label>${i18next.t('label.gross_weight')}</label>
                      <input name="grossWeight" id="grossWeightInput" type="number" min="0" step="0.001" />`
                  : ''}
              `
            : this._isRequireSerialNumberScanningOutbound && this._isBatchPicking
            ? ``
            : html`
                <label>${i18next.t('label.packed_qty')}</label>
                <input type="number" min="1" name="packedQty" />
              `}
          ${this._isRequireSerialNumberScanningOutbound && this._isBatchPicking
            ? html`
                <label>${i18next.t('label.serial_number')}</label>
                <barcode-scanable-input
                  name="serialNumber"
                  custom-input
                  @keypress="${async e => {
                    if (this._qrProcessing > 0 && e.keyCode === 13) {
                      e.preventDefault()
                      await this._processQRAndFillForm(e)
                    }
                  }}"
                ></barcode-scanable-input>
              `
            : ``}
        </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>
                ${i18next.t('title.order_no')}: ${this.releaseGoodNo}
                ${this.releaseGoodNo
                  ? html`(${this._bizplaceName})
                      <mwc-icon @click="${this.openWorksheetInformation.bind(this)}">info</mwc-icon>`
                  : ''}
                ${html`[${this._orderPackageInformation.processing}/${this._orderPackageInformation.total}]`}
              </legend>
            </fieldset>
          </form>
        </div>
      </data-grist>
    `
  }

  constructor() {
    super()
    this.data = { records: [] }
    this._orderPackageInformation = { processing: 0, total: 0 }
    this.releaseGoodNo = ''
    this.releaseGoodId = ''
    this.totalBinRO = 0
    this.checkedRemarkAt = ''
    this._enableProductScanning = false
    this._qrProcessing = 0
    this._productName = ''
    this._selectedOrderInventory = null
    this._selectedTaskStatus = null
    this._scanning = false
    this.toggleComplete = false
    this._isRequireSerialNumberScanningOutbound = false
    this._isBatchPicking = false
    this._isLmdOption = false
    this._awbAttempts = 0
    this._enablePackingGrossWeight = false
  }

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

  pageInitialized() {
    this.config = {
      rows: {
        appendable: false,
        handlers: {
          click: async (columns, data, column, record, rowIndex) => {
            if (data.records.length && record) {
              this._selectedOrderInventory = record
              this._selectedTaskStatus = record.status
              this._isRequireSerialNumberScanningOutbound = record.product.isRequireSerialNumberScanningOutbound

              if (this._enableProductScanning) this.focusOnProductBarcodeInput()
              else this.focusOnReleaseQtyInput()
            }

            this.updateContext()
          }
        }
      },
      pagination: { infinite: true },
      list: { fields: ['completed', 'locationName', 'sku', 'product', 'batchId', 'expirationDate', 'packingProgress'] },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'boolean',
          name: 'completed',
          header: i18next.t('field.done'),
          width: 40
        },
        {
          type: 'string',
          name: 'locationName',
          header: i18next.t('field.location'),
          label: true,
          width: 120
        },
        {
          type: 'string',
          name: 'sku',
          header: i18next.t('field.sku'),
          label: true,
          width: 140
        },
        {
          type: 'object',
          name: 'product',
          header: i18next.t('field.product'),
          label: true,
          width: 200
        },
        {
          type: 'string',
          name: 'packingProgress',
          header: i18next.t('field.release_qty'),
          label: true,
          width: 80
        },
        {
          type: 'string',
          name: 'batchId',
          header: i18next.t('field.batch_id'),
          label: true,
          width: 140
        },
        {
          type: 'date',
          name: 'expirationDate',
          header: i18next.t('field.exp_date'),
          label: true,
          width: 120
        }
      ]
    }
  }

  pageUpdated() {
    if (this.active) {
      this.focusOnReleaseGoodInput()
    }
  }

  async fetchInventories(releaseGoodNo) {
    if (!releaseGoodNo) return
    const response = await client.query({
      query: gql`
        query packingWorksheet($releaseGoodNo: String!) {
          packingWorksheet(releaseGoodNo: $releaseGoodNo) {
            worksheetInfo {
              releaseGood {
                id
                name
                remark
                ownTransport
                checkedRemarkAt
                totalInventoriesByBin
                isOrderInventoryBin
                lmdOption
              }
              orderPackage {
                id
                name
                packageId
                status
              }
              orderPackages {
                id
                name
                packageId
                status
              }
              bizplaceName
              partnerDomainId
              checkedRemarkBy
              refNo
              refNo2
              refNo3
              airwayBill
              invoice
              startedAt
              shippingProvider
              marketplaceStatus
              trackingNo
              source
              marketplaceOrder {
                id
                name
                orderNo
                status
                otherInfoJSON
                marketplaceStore {
                  id
                  platform
                }
                domain {
                  id
                  name
                }
              }
              platform
              isBatchPicking
            }
            worksheetDetailInfos {
              id
              name
              palletId
              cartonId
              batchId
              batchIdRef
              sku
              product {
                id
                sku
                name
                description
                gtin
                isRequireSerialNumberScanningOutbound
                productDetails {
                  id
                  packingType
                  packingSize
                  gtin
                  productBarcodes {
                    gtin
                  }
                }
              }
              qty
              releaseQty
              packedQty
              status
              targetName
              packingType
              packingSize
              binLocation {
                id
                name
              }
              relatedOrderInv {
                batchId
                batchIdRef
                packingType
                refWorksheetId
                binLocation {
                  id
                  name
                }
                product {
                  id
                  sku
                  name
                  description
                  isRequireSerialNumberScanningOutbound
                }
                productDetail {
                  id
                }
              }
            }
          }
        }
      `,
      variables: { releaseGoodNo }
    })

    if (!response.errors) {
      let releaseGood = response.data.packingWorksheet.worksheetInfo?.releaseGood
      if (releaseGood?.isOrderInventoryBin) {
        this.totalBinRO = releaseGood?.totalInventoriesByBin
        this.binRo = releaseGoodNo
      }

      this.releaseGoodNo = releaseGood?.name
      this.releaseGoodId = releaseGood?.id
      this.lmdOption = releaseGood?.lmdOption

      if (!response.data?.packingWorksheet) return

      const { worksheetInfo, worksheetDetailInfos } = response.data.packingWorksheet

      this.data = { records: this.formatWorksheetDetailInfos(worksheetDetailInfos) }

      this._orderPackageInformation = {
        processing: worksheetInfo.orderPackages.filter(op => op.status == 'DONE').length + 1 || 0,
        total: worksheetInfo.orderPackages?.length || 0,
        orderPackage: worksheetInfo.orderPackage
      }

      this.trackingNo = worksheetInfo.trackingNo
      this.airwayBill = worksheetInfo.airwayBill
      this.invoice = worksheetInfo.invoice
      this.refNo = worksheetInfo.refNo
      this.source = worksheetInfo.source
      this.platform = worksheetInfo.platform
      this.shippingProvider = worksheetInfo.shippingProvider
      this.orderInformation = worksheetInfo.marketplaceOrder
      this.orderRemark = worksheetInfo.releaseGood?.remark
      this._isLmdOption = releaseGood.lmdOption
      this.ownTransport = worksheetInfo.releaseGood?.ownTransport
      this.checkedRemarkAt = worksheetInfo.releaseGood?.checkedRemarkAt
      this.toggleComplete = Boolean(worksheetInfo.releaseGood?.remark)
        ? worksheetDetailInfos.every(res => res.status === 'DONE') &&
          worksheetInfo.releaseGood?.checkedRemarkAt !== null
        : worksheetDetailInfos.every(res => res.status === 'DONE')

      this._isBatchPicking = worksheetInfo.isBatchPicking

      this._bizplaceName = worksheetInfo.bizplaceName
      this._worksheetInfo = worksheetInfo

      if (this._selectedOrderInventory) {
        const record = this.data.records.find(record => record.name === this._selectedOrderInventory.name)
        if (record?.packedQty == record?.releaseQty) {
          this._selectedOrderInventory = null
          this._selectedTaskStatus = null
          this.inputForm.reset()
        }
      } else {
        this._selectedOrderInventory = worksheetDetailInfos[0]
        this._isRequireSerialNumberScanningOutbound =
          worksheetDetailInfos[0].product?.isRequireSerialNumberScanningOutbound
      }

      if (this.completed && this.airwayBill) {
        this.printBill()
      }

      //fetch all page settings
      let pageSettings = await fetchPageSettings({
        settings: {
          name: 'name',
          operator: 'in',
          value: ['enable-product-scanning', 'enable-packing-gross-weight', 'qr-code-scanning']
        },
        settingsDomain: this._worksheetInfo.partnerDomainId
      })

      const settingsMaps = new Map(pageSettings.settings.map(setting => [setting.name, setting.value]))

      this._enableProductScanning = settingsMaps.get('enable-product-scanning') === 'true'
      this._enablePackingGrossWeight = settingsMaps.get('enable-packing-gross-weight') === 'true'
      this._qrProcessing = settingsMaps.get('qr-code-scanning')

      if (this._enableProductScanning) {
        this.focusOnProductBarcodeInput()
      } else {
        this.focusOnReleaseQtyInput()
      }

      if (worksheetInfo.source == 'POWRUP') {
        this.fetchPowrupOrderDocument(worksheetInfo.orderPackage.id)
      }

      if (worksheetInfo.source == 'WEBSPERT') {
        this.fetchWebspertOrderDocument(worksheetInfo.orderPackage.id)
      }

      this.updateContext()
    }
  }

  formatWorksheetDetailInfos(wsdInfos) {
    return wsdInfos
      .map(record => {
        record.completed = record.status === WORKSHEET_STATUS.DONE.value
        record.locationName = record?.binLocation?.name
        record.sku = record?.sku
        record.product = record?.product
        record.packingProgress = `${record?.packedQty} / ${record.releaseQty}`

        return record
      })
      .sort((a, b) => a.completed - b.completed)
  }

  clearView() {
    this.data = { records: [] }
    this.infoForm.reset()
    this.inputForm.reset()
    this.releaseGoodNo = ''
    this._selectedOrderInventory = null
    this._selectedTaskStatus = null
    this.toggleComplete = false
  }

  checkShippingProviderAndDeliveryType() {
    if (this.orderInformation.otherInfoJSON == null) {
      return false
    } else {
      const otherInfo = JSON.parse(this.orderInformation.otherInfoJSON)

      return Boolean(otherInfo.shippingProvider && otherInfo.deliveryType)
    }
  }

  getShippingProvider() {
    const otherInfo = JSON.parse(this.orderInformation.otherInfoJSON)

    return otherInfo.shippingProvider
  }

  getDeliveryType() {
    const otherInfo = JSON.parse(this.orderInformation.otherInfoJSON)

    return otherInfo.deliveryType
  }

  async printSellercraftDocument(type) {
    try {
      if (this.releaseGoodId == undefined) {
        throw new Error('Unable to find order id, please rescan your order.')
      }

      // Increment the attempt count
      if (type === 'awb') {
        this._awbAttempts++
      }

      // get sellercraft document fetcher function
      let fetchOrder = async id => {
        const response = await client.mutate({
          mutation: gql`
            mutation fetchSellercraftDocument($orderPackageId: String!) {
              fetchSellercraftDocument(orderPackageId: $orderPackageId) {
                airwayBill
                invoice
              }
            }
          `,
          variables: { orderPackageId: id }
        })
        if (!response.errors) {
          const { invoice, airwayBill } = response.data.fetchSellercraftDocument
          this.invoice = invoice
          this.airwayBill = airwayBill
          return { invoice, airwayBill }
        }
      }

      let convertedPdfUrl = ''
      if (type == 'invoice') {
        let invoice = this.invoice
        // fetch and set variable if invoice not found
        if (!invoice || invoice.trim() == '') {
          let document = await fetchOrder(this._orderPackageInformation.orderPackage.id)
          invoice = document.invoice
        }
        if (!invoice || invoice.trim() === '') throw new Error('Document not available')
        let url = new URL(window.location)
        convertedPdfUrl = `${url.origin}/proxy?url=${invoice}`
      } else if (type == 'awb') {
        let airwayBill = this.airwayBill
        // fetch and set variable if awb not found
        if (!airwayBill || airwayBill.trim() == '') {
          let document = await fetchOrder(this._orderPackageInformation.orderPackage.id)
          airwayBill = document.airwayBill
        }
        if (!airwayBill || airwayBill.trim() === '') throw new Error('Document not available')
        if (airwayBill.includes('partner.shopeemobile.com')) {
          convertedPdfUrl = `/pdf/merge?urls=${airwayBill}`
        } else {
          let url = new URL(window.location)
          convertedPdfUrl = `${url.origin}/proxy?url=${airwayBill}`
        }
      }

      // print PDF document
      this.callPrintDialog(convertedPdfUrl)
    } catch (error) {
      if (this._awbAttempts < 4) {
        this.showToast({
          message: 'Oops! The AWB is not ready yet. Please retry by clicking the Print Airway bill button.'
        })
      } else {
        this.showToast({
          message:
            'It appears that we are unable to retrieve the AWB from the platform. Please reach out to support for assistance.'
        })
      }
    }
  }

  async printB2cDocument(type) {
    try {
      let convertedPdfUrl = ''

      // Increment the attempt count for AWB
      if (type === 'awb') {
        if (!this._awbAttempts) this._awbAttempts = 0
        this._awbAttempts++
      }

      if (type == 'invoice') {
        let invoice = this.invoice
        if (!invoice || String(invoice).trim() === '') throw new Error('Document not available')
        if (isValidHttpUrl(invoice)) {
          let url = new URL(window.location)
          convertedPdfUrl = `${url.origin}/proxy?url=${invoice}`
        } else {
          convertedPdfUrl = `${location.origin}/attachment/${invoice}`
        }
      } else if (type == 'awb') {
        let airwayBill = this.airwayBill
        if (!airwayBill || String(airwayBill).trim() === '') throw new Error('Document not available')
        if (airwayBill.includes('partner.shopeemobile.com')) {
          convertedPdfUrl = `/pdf/merge?urls=${airwayBill}`
        } else if (isValidHttpUrl(airwayBill)) {
          let url = new URL(window.location)
          convertedPdfUrl = `${url.origin}/proxy?url=${airwayBill}`
        } else {
          convertedPdfUrl = `${location.origin}/attachment/${airwayBill}`
        }
      }

      this.callPrintDialog(convertedPdfUrl)
    } catch (error) {
      // Error handling based on AWB attempts
      if (this._awbAttempts < 4) {
        this.showToast({
          message: 'Oops! The AWB is not ready yet. Please retry by clicking the Print Airway bill button.'
        })
      } else {
        this.showToast({
          message:
            'It appears that we are unable to retrieve the AWB from the platform. Please reach out to support for assistance.'
        })
      }
    }
  }

  async printPowrupDocument(type) {
    try {
      if (this._orderPackageInformation.orderPackage.id == undefined) {
        throw new Error('Unable to find package id, please rescan your order.')
      }

      // Increment the attempt count
      if (type === 'awb') {
        this._awbAttempts++
      }

      let convertedPdfUrl = ''
      if (type == 'invoice') {
        let invoice = this.invoice
        // fetch and set variable if invoice not found
        if (!invoice || invoice.trim() == '') {
          let document = await this.fetchPowrupOrderDocument(this._orderPackageInformation.orderPackage.id)
          invoice = document.invoice
        }
        if (!invoice || invoice.trim() === '') throw new Error('Document not available')
        let url = new URL(window.location)
        convertedPdfUrl = `${url.origin}/proxy?url=${invoice}`
      } else if (type == 'awb') {
        let airwayBill = this.airwayBill
        // fetch and set variable if awb not found
        if (!airwayBill || airwayBill.trim() == '') {
          let document = await this.fetchPowrupOrderDocument(this._orderPackageInformation.orderPackage.id)
          airwayBill = document.airwayBill
        }
        if (!airwayBill || airwayBill.trim() === '') throw new Error('Document not available')
        if (airwayBill.includes('partner.shopeemobile.com')) {
          convertedPdfUrl = `/pdf/merge?urls=${airwayBill}`
        } else {
          let url = new URL(window.location)
          convertedPdfUrl = `${url.origin}/proxy?url=${airwayBill}`
        }
      }

      // print PDF document
      this.callPrintDialog(convertedPdfUrl)
    } catch (error) {
      if (this._awbAttempts < 4) {
        this.showToast({
          message: 'Oops! The AWB is not ready yet. Please retry by clicking the Print Airway bill button.'
        })
      } else {
        this.showToast({
          message:
            'It appears that we are unable to retrieve the AWB from the platform. Please reach out to support for assistance.'
        })
      }
    }
  }

  // get powrup document fetcher function
  async fetchPowrupOrderDocument(id) {
    const response = await client.mutate({
      mutation: gql`
        mutation fetchPowrupDocument($orderPackageId: String!) {
          fetchPowrupDocument(orderPackageId: $orderPackageId) {
            airwayBill
            invoice
          }
        }
      `,
      variables: { orderPackageId: id }
    })
    if (!response.errors) {
      const { invoice, airwayBill } = response.data.fetchPowrupDocument
      this.invoice = invoice
      this.airwayBill = airwayBill
      return { invoice, airwayBill }
    }
  }

  async printWebspertDocument(type) {
    try {
      if (this._orderPackageInformation.orderPackage.id == undefined) {
        throw new Error('Unable to find package id, please rescan your order.')
      }

      // Increment the attempt count
      if (type === 'awb') {
        this._awbAttempts++
      }

      let convertedPdfUrl = ''
      if (type == 'invoice') {
        let invoice = this.invoice
        // fetch and set variable if invoice not found
        if (!invoice || invoice.trim() == '') {
          let document = await this.fetchWebspertOrderDocument(this._orderPackageInformation.orderPackage.id)
          invoice = document.invoice
        }
        if (!invoice || invoice.trim() === '') throw new Error('Document not available')
        let url = new URL(window.location)
        convertedPdfUrl = `${url.origin}/proxy?url=${invoice}`
      } else if (type == 'awb') {
        let airwayBill = this.airwayBill
        // fetch and set variable if awb not found
        if (!airwayBill || airwayBill.trim() == '') {
          let document = await this.fetchWebspertOrderDocument(this._orderPackageInformation.orderPackage.id)
          airwayBill = document.airwayBill
        }
        if (!airwayBill || airwayBill.trim() === '') throw new Error('Document not available')
        if (airwayBill.includes('partner.shopeemobile.com')) {
          convertedPdfUrl = `/pdf/merge?urls=${airwayBill}`
        } else {
          let url = new URL(window.location)
          convertedPdfUrl = `${url.origin}/proxy?url=${airwayBill}`
        }
      }

      // print PDF document
      this.callPrintDialog(convertedPdfUrl)
    } catch (error) {
      if (this._awbAttempts < 4) {
        this.showToast({
          message: 'Oops! The AWB is not ready yet. Please retry by clicking the Print Airway bill button.'
        })
      } else {
        this.showToast({
          message:
            'It appears that we are unable to retrieve the AWB from the platform. Please reach out to support for assistance.'
        })
      }
    }
  }

  // get webspert document fetcher function
  async fetchWebspertOrderDocument(id) {
    const response = await client.mutate({
      mutation: gql`
        mutation fetchWebspertDocument($orderPackageId: String!) {
          fetchWebspertDocument(orderPackageId: $orderPackageId) {
            airwayBill
            invoice
          }
        }
      `,
      variables: { orderPackageId: id }
    })
    if (!response.errors) {
      const { invoice, airwayBill } = response.data.fetchWebspertDocument
      this.invoice = invoice
      this.airwayBill = airwayBill
      return { invoice, airwayBill }
    }
  }

  async printInvoice() {
    var orderDocInfo = await this.getOrderDocument(this.refNo, 'invoice')

    if (orderDocInfo?.length === 0) {
      this.showToast({ message: i18next.t('text.no_document_available') })
    } else {
      switch (this.platform) {
        case 'lazada':
          var decodedHTML = atob(orderDocInfo[0].file)
          this.callPrintDialog(decodedHTML)
          break
      }
    }
  }

  async packingList() {
    const timezoneOffset = new Date().getTimezoneOffset().toString()
    const response = await client.query({
      query: gql`
        query packingList($orderPackageId: String!, $numberOfOrderProcessing: Int, $timezoneOffset: String) {
          packingList(
            orderPackageId: $orderPackageId
            numberOfOrderProcessing: $numberOfOrderProcessing
            timezoneOffset: $timezoneOffset
          ) {
            packingList
          }
        }
      `,
      variables: {
        orderPackageId: this._orderPackageInformation.orderPackage.id,
        numberOfOrderProcessing: this._orderPackageInformation.processing,
        timezoneOffset: timezoneOffset
      }
    })
    let htmlContent = Buffer.from(response.data.packingList.packingList, 'base64').toString()
    this.callPrintPackingDialog(htmlContent)
  }

  async printAirwayBill() {
    try {
      // Initialize or increment the AWB attempts
      if (!this._awbAttempts) this._awbAttempts = 0
      this._awbAttempts++

      var orderDocInfo = await this.getOrderDocument(this.refNo, 'shippingLabel')

      if (!orderDocInfo || orderDocInfo.length === 0) {
        throw new Error('Document not available')
      } else {
        let content
        if (this.platform == 'shopee' && !orderDocInfo[0]?.isShopeeV2) {
          const orderDocUrls = orderDocInfo.map(item => item.airwayBill).filter(url => url && String(url).trim() !== '')
          if (orderDocUrls.length === 0) throw new Error('Document not available')
          for (var i = 0; i < orderDocUrls.length; i++) {
            orderDocUrls[i] = 'urls=' + orderDocUrls[i]
          }
          let mergedURL = orderDocUrls.toString().replace(/,/g, '&')
          content = `/pdf/merge?${mergedURL}`
        }
        // else if (this.platform == 'lazada') {
        //   content = atob(orderDocInfo[0].file)
        // }
        else {
          let url = new URL(window.location)
          const awb = orderDocInfo[0]?.airwayBill
          if (!awb || String(awb).trim() === '') throw new Error('Document not available')
          content = `${url.origin}/proxy?url=${encodeURIComponent(awb)}`
        }
        this.callPrintDialog(content)
      }
    } catch (error) {
      // Error handling based on AWB attempts
      if (this._awbAttempts < 4) {
        this.showToast({
          message: 'Oops! The AWB is not ready yet. Please retry by clicking the Print Airway bill button.'
        })
      } else {
        this.showToast({
          message:
            'It appears that we are unable to retrieve the AWB from the platform. Please reach out to support for assistance.'
        })
      }
    }
  }

  async getOrderDocument(orderNo, docType) {
    try {
      const response = await client.query({
        query: gql`
          query getOrderDocument($orderNo: [String!], $docType: String) {
            getOrderDocument(orderNo: $orderNo, docType: $docType) {
              orderNo
              airwayBill
              mimeType
              file
              documentType
              isShopeeV2
            }
          }
        `,
        variables: { orderNo, docType }
      })

      if (!response.errors) {
        return response.data.getOrderDocument
      }
    } catch (e) {
      this.showToast(e)
    }
  }

  async callPrintPackingDialog(contentSource) {
    GhostPrint.print({
      srcdoc: contentSource, //srcdoc is used to convert html to pdf
      pending: 1000,
      onfinish: () => {
        this.showToast({ message: i18next.t('text.document_has_been_generated') })
      }
    })
  }

  async callPrintDialog(contentSource) {
    if (
      !contentSource ||
      (typeof contentSource === 'string' && contentSource.trim() === '') ||
      contentSource === 'undefined'
    ) {
      this.showToast({ type: 'warning', message: i18next.t('text.no_document_available') })
      return
    }
    switch (this.platform) {
      //this condition is to select based on the content type
      //for html content will be using srcdoc
      //for url content will be using src
      case 'lazada':
        GhostPrint.print({
          srcdoc: contentSource, //srcdoc is used to convert html to pdf
          pending: 1000,
          onfinish: () => {
            this.showToast({ message: i18next.t('text.document_has_been_generated') })
          }
        })
        break

      case 'shopee':
      default:
        GhostPrint.print({
          src: contentSource, //src is use to convert url to pdf
          pending: 1000,
          onfinish: () => {
            this.showToast({ message: i18next.t('text.document_has_been_generated') })
          }
        })
        break
    }
  }

  async _processQRAndFillForm(e) {
    // QR scanning
    if (
      this._enableProductScanning &&
      this._qrProcessing > 0 &&
      (isValidHttpUrl(this.productBarcodeInput?.value) || isValidHttpUrl(this.serialInput?.value))
    ) {
      let input = isValidHttpUrl(this.productBarcodeInput?.value)
        ? this.productBarcodeInput?.value
        : this.serialInput?.value
      let config = JSON.parse(
        await fetchSettingRule('qr-data-parsing-configuration', this._worksheetInfo.partnerDomainId)
      )
      // Get GTIN and serial number from QR code
      let data = await decodeQR(input, config)

      // Fill up form
      if (this.productBarcodeInput && data.productBarcode) {
        this.productBarcodeInput.value = data.productBarcode
      }
      if (this.serialInput && data.serialNumber) {
        this.serialInput.value = data.serialNumber
      }

      await sleep(1010)

      this.packing(e)
    }
  }

  async packing(e) {
    if (e.keyCode === 13) {
      e.preventDefault()
      console.time('time execution for product barcode scanning')

      try {
        await this.validatePacking()

        let response = this._enableProductScanning ? await this.productBarcodePacking() : await this.commonPacking()

        console.timeLog('time execution for product barcode scanning')

        if (!response.errors) {
          if (this._enableProductScanning) {
            this.productBarcodeInput.value = ''
            if (this._enablePackingGrossWeight) {
              this.grossWeightInput.value = ''
            }
          } else {
            this.releaseQtyInput.value = ''
            this._selectedTaskStatus = null
            this._selectedOrderInventory = null
          }
          if (this._isRequireSerialNumberScanningOutbound && this._isBatchPicking) {
            this.serialInput.value = ''
          }

          if (!this._enableProductScanning) {
            this.fetchInventories(this.releaseGoodNo)
          }
        }
      } catch (e) {
        if (this._isRequireSerialNumberScanningOutbound && this._isBatchPicking) this.serialInput.value = ''
        else if (this._enableProductScanning && !this._isRequireSerialNumberScanningOutbound) {
          this.focusOnProductBarcodeInput()
        } else {
          this.focusOnReleaseQtyInput()
          this._selectedTaskStatus = null
        }
        //this._selectedOrderInventory = null

        this.showToast(e)
      } finally {
        if (!this._isRequireSerialNumberScanningOutbound) {
          this._enableProductScanning ? (this.productBarcodeInput.value = '') : (this.releaseQtyInput.value = '')
          if (this._enablePackingGrossWeight) {
            this.grossWeightInput.value = ''
          }
        } else {
          if (this._isBatchPicking) this.serialInput.value = ''
        }

        if (!this._selectedOrderInventory) {
          this._selectedOrderInventory = this.data.records[0]
          this._isRequireSerialNumberScanningOutbound =
            this.data.records[0].product?.isRequireSerialNumberScanningOutbound
        }
        // time execution for product barcode scanning (without scanning machines): 308.0390625 ms
        console.timeEnd('time execution for product barcode scanning')
      }
    }
  }

  async productBarcodePacking() {
    if (this._scanning) throw new Error(i18next.t('text.previous_scan_is_executing'))
    this._scanning = true

    try {
      let response = await client.mutate({
        mutation: gql`
          mutation scanProductPacking($orderPackageItemId: String!, $productBarcode: String!, $serialNumber: String) {
            scanProductPacking(
              orderPackageItemId: $orderPackageItemId
              productBarcode: $productBarcode
              serialNumber: $serialNumber
            ) {
              worksheetDetailInfos {
                id
                name
                palletId
                cartonId
                batchId
                batchIdRef
                sku
                product {
                  id
                  name
                  description
                  gtin
                  isRequireSerialNumberScanningOutbound
                  productDetails {
                    id
                    packingType
                    packingSize
                    gtin
                  }
                }
                qty
                releaseQty
                packedQty
                status
                targetName
                packingType
                packingSize
                binLocation {
                  name
                }
                relatedOrderInv {
                  batchId
                  batchIdRef
                  packingType
                  refWorksheetId
                  product {
                    id
                    sku
                    name
                    description
                    isRequireSerialNumberScanningOutbound
                  }
                }
              }
            }
          }
        `,
        variables: {
          orderPackageItemId: this._selectedOrderInventory.id,
          productBarcode: this.productBarcodeInput.value.trim(),
          serialNumber:
            this._isRequireSerialNumberScanningOutbound && this._isBatchPicking ? this.serialInput.value.trim() : null
        }
      })

      if (!response.errors) {
        const { worksheetDetailInfos } = response.data.scanProductPacking

        //will change for the next enhancement
        let rec = this.data.records.map(data => {
          let ids = data.id.split(',').map(id => id.trim())
          let info = worksheetDetailInfos.find(wd => ids.includes(wd.id))
          if (info) {
            if (info?.packedQty <= data.packedQty) {
              let newPackQty = data?.packedQty + 1
              return {
                ...data,
                packingProgress: `${newPackQty} / ${data.releaseQty}`,
                packedQty: newPackQty,
                status: newPackQty === data.releaseQty ? 'DONE' : 'PROCESSING',
                completed: newPackQty === data.releaseQty
              }
            } else {
            }
            return {
              ...data,
              packingProgress: `${info?.packedQty} / ${data.releaseQty}`,
              packedQty: info.packedQty,
              status: info.packedQty === data.releaseQty ? 'DONE' : 'PROCESSING',
              completed: info.packedQty === data.releaseQty
            }
          } else {
            return data
          }
        })
        this.data = { records: rec.sort((a, b) => a.completed - b.completed) }

        this.toggleComplete = Boolean(this.releaseGood?.remark)
          ? this.data.records.every(res => res.status === 'DONE') && worksheetInfo.releaseGood?.checkedRemarkAt !== null
          : this.data.records.every(res => res.status === 'DONE')

        if (this.toggleComplete) this.fetchInventories(this.releaseGoodNo)

        if (this._selectedOrderInventory) {
          const record = this.data.records.find(record => record.name === this._selectedOrderInventory.name)
          if (record?.packedQty == record?.releaseQty) {
            this._selectedOrderInventory = null
            this._selectedTaskStatus = null
            this.inputForm.reset()
          }
        } else {
          this._selectedOrderInventory = this.data.records[0]
          this._isRequireSerialNumberScanningOutbound =
            this.data.records[0].product?.isRequireSerialNumberScanningOutbound
        }

        if (this._enableProductScanning) {
          this.focusOnProductBarcodeInput()
        } else {
          this.focusOnReleaseQtyInput()
        }

        this.updateContext()
      }

      return response
    } catch (e) {
      this.showToast(e)
    } finally {
      this._scanning = false
    }
  }

  async commonPacking() {
    if (this._scanning) throw new Error(i18next.t('text.previous_scan_is_executing'))
    this._scanning = true

    try {
      return await client.mutate({
        mutation: gql`
          mutation packing($orderPackageItemId: String!, $releaseQty: Int!, $serialNumber: String) {
            packing(orderPackageItemId: $orderPackageItemId, releaseQty: $releaseQty, serialNumber: $serialNumber)
          }
        `,
        variables: {
          orderPackageItemId: this._selectedOrderInventory.id,
          releaseQty:
            this._isRequireSerialNumberScanningOutbound && this._isBatchPicking
              ? 1
              : parseInt(this.releaseQtyInput.value),
          serialNumber:
            this._isRequireSerialNumberScanningOutbound && this._isBatchPicking ? this.serialInput.value.trim() : null
        }
      })
    } catch (e) {
      this.showToast(e)
    } finally {
      this._scanning = false
    }
  }

  validatePacking() {
    // validate for order selection
    if (this._enableProductScanning) {
      //if entered weight without fully scanning product barcode and settings enabled
      if (
        this._enablePackingGrossWeight &&
        this.grossWeightInput.value &&
        this._selectedOrderInventory?.packedQty !== this._selectedOrderInventory?.releaseQty
      ) {
        this._selectedOrderInventory = null
        throw new Error(i18next.t('text.please_scan_all_items_first_before_entering_the_gross_weight'))
      }

      if (
        !this.productBarcodeInput.value &&
        this._selectedOrderInventory?.packedQty !== this._selectedOrderInventory?.releaseQty
      ) {
        this.focusOnProductBarcodeInput()
        throw new Error(i18next.t('text.no_product_barcode_detected'))
      }

      //find product match with input barcode
      const foundOrderInventory = this.data.records.find(
        itm =>
          itm.product.productDetails.find(detail =>
            detail.productBarcodes.find(pb => pb.gtin === this.productBarcodeInput.value.trim())
          ) != undefined
      )

      if (foundOrderInventory) {
        this._selectedOrderInventory = foundOrderInventory

        if (this._selectedOrderInventory?.packedQty === this._selectedOrderInventory?.releaseQty) {
          this._selectedOrderInventory = null
          throw new Error(i18next.t('text.scanned_product_status_is_done'))
        }
      } else {
        this.focusOnProductBarcodeInput()
        throw new Error(i18next.t('text.incorrect_product_barcode'))
      }
    } else {
      if (!this._selectedOrderInventory) throw new Error(i18next.t('text.target_is_not_selected'))

      if (!this.releaseQtyInput.checkValidity()) throw new Error(i18next.t('text.release_qty_invalid'))

      // Release qty existing
      if (!parseFloat(this.releaseQtyInput.value)) {
        this.focusOnReleaseQtyInput()
        throw new Error(i18next.t('text.release_qty_is_empty'))
      }

      // typed qty should be matched with release qty.
      if (parseFloat(this.releaseQtyInput.value) !== this._selectedOrderInventory.releaseQty) {
        this.focusOnReleaseQtyInput()
        throw new Error(i18next.t('text.wrong_release_qty'))
      }
    }

    if (this._isRequireSerialNumberScanningOutbound && this._isBatchPicking) {
      if (!this.serialInput?.value) {
        this.focusOnSerialInput()
        throw new Error(i18next.t('text.empty_serial_number'))
      }
    }
  }

  async complete() {
    if (this._enablePackingGrossWeight) {
      const grossWeightValue = this.grossWeightInput.value

      if (!grossWeightValue) {
        throw new Error(
          this.showToast({
            message: i18next.t('text.please_input_the_gross_weight_to_proceed_with_complete_packing')
          })
        )
      }

      if (!/^\d*\.?\d*$/.test(grossWeightValue)) {
        throw new Error(
          this.showToast({
            message: i18next.t('text.please_input_a_positive_gross_weight_to_proceed_with_complete_packing')
          })
        )
      }
    }

    const response = await client.mutate({
      mutation: gql`
        mutation completePacking($releaseGoodNo: String!, $orderPackageId: String!, $grossWeight: Float) {
          completePacking(releaseGoodNo: $releaseGoodNo, orderPackageId: $orderPackageId, grossWeight: $grossWeight)
        }
      `,
      variables: {
        releaseGoodNo: this.releaseGoodNo,
        orderPackageId: this._orderPackageInformation?.orderPackage?.id,
        grossWeight:
          this._enablePackingGrossWeight && this.grossWeightInput.value ? parseFloat(this.grossWeightInput.value) : null
      }
    })

    if (!response.errors) {
      if (this.totalBinRO > 1) {
        const resultNextOrder = await CustomAlert({
          title: i18next.t('title.packing'),
          text: i18next.t('text.packing_is_completed'),
          confirmButton: { text: i18next.t('button.next_order') }
        })

        if (!resultNextOrder.value) {
          this.focusOnReleaseGoodInput()
          this.clearView()
          this.updateContext()
          return
        }

        this.clearView()
        this.updateContext()

        this.checkedRemarkAt = ''
        await this.fetchInventories(this.binRo)
        this.toggleComplete = false
        if (this._enableProductScanning) this.focusOnProductBarcodeInput()
      } else {
        this.toggleComplete = false

        this.clearView()
        this.updateContext()

        const result = await CustomAlert({
          title: i18next.t('title.packing'),
          text: i18next.t('text.packing_is_completed'),
          timer: 1000
        })

        if (result.dismiss === 'timer' && result.isDismissed) {
          this.focusOnReleaseGoodInput()
        }
      }
    }
  }

  async openOrderRemarkPopup() {
    await sleep(1010)
    openPopup(
      html`
        <order-remark-popup
          .orderRemark="${this.orderRemark}"
          .releaseGoodNo="${this.releaseGoodNo}"
          .checkedRemarkAt="${this.checkedRemarkAt}"
          @remark-checked="${async () => {
            await this.fetchInventories(this.releaseGoodNo)
            this.showToast({ message: i18next.t('text.order_remark_has_been_checked') })
          }}"
        ></order-remark-popup>
      `,
      {
        backdrop: true,
        size: 'medium',
        title: i18next.t('title.order_remark')
      }
    )
  }

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

  async printBill() {
    if (this.releaseGoodNo && this.platform != 'operato' && this.completed && this.trackingNo) {
      await this.printAirwayBill()
    }

    if (
      this.releaseGoodNo &&
      this.platform == 'operato' &&
      this.source == 'SELLERCRAFT' &&
      this.airwayBill &&
      this.completed
    ) {
      await this.printSellercraftDocument('awb')
    }

    if (this.releaseGoodNo && this.airwayBill && this.completed) {
      switch (this.source) {
        case 'POWRUP':
          await this.printPowrupDocument('awb')
          break

        case 'WEBSPERT':
          await this.printWebspertDocument('awb')
          break
      }
    }

    if (
      this.releaseGoodNo &&
      (this.source == 'OTHERS' || this.source == null) &&
      this.platform == 'operato' &&
      this.completed
    ) {
      await this.printB2cDocument('awb')
    }
  }

  async openSerialNumberPopup() {
    await sleep(1010)
    let qrConfig = null
    if (this._qrProcessing > 0) {
      qrConfig = JSON.parse(
        await fetchSettingRule('qr-data-parsing-configuration', this._worksheetInfo.partnerDomainId)
      )
    }
    openPopup(
      html`
        <packing-serial-number-popup
          .orderType="${i18next.t('text.outbound')}"
          .orderSource="${ORDER_SOURCES.PACKING.value}"
          .orderId="${this.releaseGoodId}"
          .orderPackageId="${this._orderPackageInformation?.orderPackage?.id}"
          .qrProcessing="${this._qrProcessing}"
          .qrConfig="${qrConfig}"
          @close-serial-number-popup="${async e => {
            await this.fetchInventories(this.releaseGoodNo)
          }}"
        ></packing-serial-number-popup>
      `,
      {
        closable: false,
        backdrop: false,
        escapable: false,
        size: 'large',
        title: i18next.t('title.serial_number_list')
      }
    )
  }

  async setOrderToRTS() {
    let result = await CustomAlert({
      title: i18next.t('title.are_you_sure'),
      text: i18next.t('text.set_order_to_ready_to_ship'),
      confirmButton: { text: i18next.t('button.confirm') },
      cancelButton: { text: i18next.t('button.cancel') }
    })

    if (!result.value) return

    try {
      let response

      if (this.orderInformation.marketplaceStore.platform === PLATFORM.LAZADA.value) {
        response = await client.mutate({
          mutation: gql`
            mutation updateOrderReadyToShip(
              $shippingProvider: String!
              $deliveryType: String!
              $orderNo: String!
              $orderId: String!
              $domainId: String!
            ) {
              updateOrderReadyToShip(
                shippingProvider: $shippingProvider
                deliveryType: $deliveryType
                orderNo: $orderNo
                orderId: $orderId
                domainId: $domainId
              )
            }
          `,
          variables: {
            shippingProvider: this.getShippingProvider(),
            deliveryType: this.getDeliveryType(),
            orderNo: this.orderInformation.orderNo,
            orderId: this.orderInformation.name,
            domainId: this.orderInformation.domain.id
          }
        })
      }

      if (
        this.orderInformation.marketplaceStore.platform === PLATFORM.SHOPIFY.value ||
        this.orderInformation.marketplaceStore.platform === PLATFORM.WOOCOMMERCE.value
      ) {
        response = await client.mutate({
          mutation: gql`
            mutation updateOrderReadyToShip($orderNo: String!, $orderId: String!, $domainId: String!) {
              updateOrderReadyToShip(orderNo: $orderNo, orderId: $orderId, domainId: $domainId)
            }
          `,
          variables: {
            orderNo: this.orderInformation.orderNo,
            orderId: this.orderInformation.name,
            domainId: this.orderInformation.domain.id
          }
        })
      }

      if (!response.errors) {
        this.showToast({ message: i18next.t('text.order_has_been_set_to_ready_to_ship') })
      }
    } catch (e) {
      this.showToast(e)
    }
  }

  showToast(payload) {
    const normalized = typeof payload === 'string' ? { message: payload } : payload || {}
    const notifyType = normalized.type || 'error'
    const notifyMessage = normalized.message || i18next.t('text.no_document_available')
    document.dispatchEvent(
      new CustomEvent('notify', {
        detail: {
          type: notifyType,
          message: notifyMessage
        }
      })
    )
  }
}

window.customElements.define('packing-product', PackingProduct)
