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

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

import { i18next, localize } from '@things-factory/i18n-base'
import { openPopup } from '@things-factory/layout-base'
import { client, CustomAlert } from '@things-factory/shell'
import { ScrollbarStyles } from '@things-factory/styles'
import { isMobileDevice } from '@things-factory/utils'
import { fetchSettingRule } from '../../../fetch-setting-value'

import { ORDER_PRODUCT_STATUS } from '../../constants'

export class EditProductPopup extends localize(i18next)(LitElement) {
  static get styles() {
    return [
      ScrollbarStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow: hidden;
          background-color: white;
        }
        .grist {
          display: flex;
          flex-direction: column;
          flex: 1;
          overflow-y: auto;
        }
        .grist h2 mwc-icon {
          vertical-align: middle;
          margin: var(--grist-title-icon-margin);
          font-size: var(--grist-title-icon-size);
          color: var(--grist-title-icon-color);
        }
        .grist-container {
          overflow-y: hidden;
          display: flex;
          flex: 1;
        }
        data-grist {
          overflow-y: hidden;
          flex: 1;
        }
        h2 {
          padding: var(--subtitle-padding);
          font: var(--subtitle-font);
          color: var(--subtitle-text-color);
          border-bottom: var(--subtitle-border-bottom);
        }
        .grist h2 {
          font: var(--grist-title-font);
        }
        .button-container {
          padding: var(--button-container-padding);
          margin: var(--button-container-margin);
          text-align: var(--button-container-align);
          background-color: var(--button-container-background);
          height: var(--button-container-height);
        }

        .hidden {
          display: none;
        }
        [danger] {
          --mdc-theme-primary: var(--mdc-danger-button-primary-color);
        }
      `
    ]
  }

  static get properties() {
    return {
      ganNo: String,
      status: String,
      bizplace: Object,
      editProductConfig: Object,
      addProductConfig: Object,
      productData: Object,
      newProductData: Object,
      strictEditable: Boolean,
      userRole: Array,
      enableDirectInbound: Boolean
    }
  }

  render() {
    return html`
      <div class="grist-container">
        <div class="grist">
          <h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.edit_product')}</h2>
          <data-grist
            id="editProduct"
            .mode="${isMobileDevice() ? 'LIST' : 'GRID'}"
            .config="${this.editProductConfig}"
            .data="${this.productData}"
            @record-change="${this._onProductChangeHandler.bind(this)}"
          ></data-grist>
        </div>

        <div class="grist">
          <h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.add_product')}</h2>
          <data-grist
            id="addProduct"
            .mode="${isMobileDevice() ? 'LIST' : 'GRID'}"
            .config="${this.addProductConfig}"
            .data="${this.newProductData}"
            @record-change="${this._onProductChangeHandler.bind(this)}"
          ></data-grist>
        </div>
      </div>

      <div class="button-container">
        <mwc-button
          raised
          danger
          @click=${() => {
        history.back()
      }}
          label="${i18next.t('button.cancel')}"
        ></mwc-button>
        <mwc-button
          raised
          @click="${this._addEditProducts.bind(this, false)}"
          label="${i18next.t('button.submit_for_approval')}"
          class="${this.status === 'PENDING' ? 'hidden' : ''}"
        ></mwc-button>
        <mwc-button
          type="button"
          raised
          @click="${this._addEditProducts.bind(this, true)}"
          label="${i18next.t('button.submit')}"
          class="${this.status !== 'PENDING' ? 'hidden' : ''}"
        ></mwc-button>
      </div>
    `
  }

  constructor() {
    super()
    this.productData = { records: [] }
    this.newProductData = { records: [] }
  }

  async firstUpdated() {
    this.enableLotIdInput = await fetchSettingRule('enable-lot-id-input')
    this.enableDirectInbound = await fetchSettingRule('enable-direct-gan-order')

    const fields = [
      'batchId',
      'productSku',
      'product',
      'brand',
      'packingType',
      'uomValue',
      'uom',
      'packQty',
      'totalUomValue',
      'palletQty',
      'palletId',
      'expDate',
      'manufactureDate',
      'batchIdRef',
      'warehouse',
      'location',
      'unitPrice',
      'remark',
      'status'
    ]

    const columns = [
      { type: 'gutter', gutterName: 'sequence' },
      { type: 'string', name: 'id', hidden: true },
      {
        type: 'string',
        name: 'batchId',
        header: i18next.t('field.batch_id'),
        record: { editable: true },
        width: 150
      },
      {
        type: 'string',
        name: 'productSku',
        header: i18next.t('field.sku'),
        width: 150
      },
      {
        type: 'object',
        name: 'product',
        header: i18next.t('field.product'),
        width: 350
      },
      {
        type: 'object',
        name: 'brand',
        header: i18next.t('field.brand'),
        width: 150
      },
      {
        type: 'code',
        name: 'packingType',
        header: i18next.t('field.packing_type'),
        record: { editable: !this.strictEditable, codeName: 'PACKING_TYPES' },
        width: 150
      },
      {
        type: 'float',
        name: 'uomValue',
        header: i18next.t('field.uom_value'),
        record: { editable: !this.strictEditable, options: { min: 0 } },
        width: 80
      },
      {
        type: 'code',
        name: 'uom',
        header: i18next.t('field.uom'),
        record: { editable: !this.strictEditable, codeName: 'WEIGHT_UNITS' },
        width: 80
      },
      {
        type: 'float',
        name: 'packQty',
        header: i18next.t('field.pack_qty'),
        record: { editable: true, options: { min: 0 } },
        width: 80
      },
      {
        type: 'float',
        name: 'totalUomValue',
        header: i18next.t('field.total_uom_value'),
        width: 120
      },
      {
        type: 'integer',
        name: 'palletQty',
        header: i18next.t('field.pallet_qty'),
        record: { editable: true, options: { min: 0 } },
        width: 80
      },
      ...(this._enableLotIdInput
        ? [
          {
            type: 'string',
            name: 'palletId',
            header: i18next.t('field.lot_id'),
            imex: { header: i18next.t('field.lot_id'), key: 'palletId', width: 25, type: 'string' },
            record: { editable: true },
            width: 150
          }
        ]
        : []),
      {
        type: 'date',
        name: 'manufactureDate',
        header: i18next.t('field.manufacture_date'),
        record: { editable: true },
        width: 120
      },
      {
        type: 'string',
        name: 'batchIdRef',
        header: i18next.t('field.batch_no_ref'),
        record: { editable: true },
        width: 150
      },
      {
        type: 'float',
        name: 'unitPrice',
        header: i18next.t('field.unit_price'),
        record: { editable: true },
        width: 80
      },
      {
        type: 'string',
        name: 'remark',
        header: i18next.t('field.remark'),
        record: { editable: true },
        width: 300
      },
      {
        type: 'string',
        name: 'status',
        header: i18next.t('field.status'),
        width: 130
      }
    ]

    function insertAfter(cols, anchorName, newCols) {
      const idx = cols.findIndex(c => c.name === anchorName)
      if (idx >= 0) cols.splice(idx + 1, 0, ...newCols)
    }

    function createExpDateColumn() {
      return {
        type: 'date',
        name: 'expDate',
        header: i18next.t('field.exp_date'),
        record: { editable: true },
        width: 120
      }
    }

    function createWarehouseColumn() {
      return {
        type: 'object',
        name: 'warehouse',
        header: i18next.t('field.warehouse'),
        width: 150
      }
    }

    function createLocationColumn(clickHandler) {
      return {
        type: 'object',
        name: 'location',
        header: i18next.t('field.location'),
        record: { editable: true },
        handlers: {
          click: (columns, data, column, record, rowIndex) => {
            clickHandler(rowIndex)
          }
        },
        width: 150
      }
    }

    if (this.enableDirectInbound) {
      const anchor = this.enableLotIdInput ? 'palletId' : 'palletQty'
      insertAfter(columns, anchor, [createExpDateColumn()])
      insertAfter(columns, 'batchIdRef', [
        createWarehouseColumn(),
        createLocationColumn(rowIndex => this._openLocationSelection(rowIndex))
      ])
    }

    this.editProductConfig = {
      pagination: { infinite: true },
      rows: { selectable: { multiple: true }, appendable: false },
      list: {
        fields
      },
      columns
    }

    const addFields = [
      'batchId',
      'productName',
      'packingType',
      'uomValue',
      'uom',
      'packQty',
      'totalUomValue',
      'palletQty',
      'palletId',
      'expDate',
      'manufactureDate',
      'batchIdRef',
      'warehouse',
      'location',
      'unitPrice',
      'remark'
    ]

    const addColumns = [
      { type: 'gutter', gutterName: 'sequence' },
      {
        type: 'gutter',
        gutterName: 'button',
        icon: 'close',
        handlers: {
          click: (columns, data, column, record, rowIndex) => {
            const newData = data.records.filter((_, idx) => idx !== rowIndex)
            this.newProductData = { ...this.newProductData, records: newData }
            this.addProductGrist.dirtyData.records = newData
          }
        }
      },
      {
        type: 'string',
        name: 'batchId',
        header: i18next.t('field.batch_id'),
        record: { editable: true },
        width: 150
      },
      {
        type: 'string',
        name: 'productName',
        header: i18next.t('field.product'),
        imex: { header: i18next.t('field.product'), key: 'productName', width: 50, type: 'string' },
        handlers: {
          click: (columns, data, column, record, rowIndex) => {
            this._openProductSelection(rowIndex)
          }
        },
        width: 350
      },
      {
        type: 'object',
        name: 'product',
        hidden: true
      },
      {
        type: 'object',
        name: 'brand',
        header: i18next.t('field.brand'),
        width: 150
      },
      {
        type: 'code',
        name: 'packingType',
        header: i18next.t('field.packing_type'),
        record: { editable: !this.strictEditable, codeName: 'PACKING_TYPES' },
        width: 150
      },
      {
        type: 'float',
        name: 'uomValue',
        header: i18next.t('field.uom_value'),
        record: { editable: !this.strictEditable, options: { min: 0 } },
        width: 80
      },
      {
        type: 'code',
        name: 'uom',
        header: i18next.t('field.uom'),
        record: { editable: !this.strictEditable, codeName: 'WEIGHT_UNITS' },
        width: 80
      },
      {
        type: 'float',
        name: 'packQty',
        header: i18next.t('field.pack_qty'),
        record: { editable: true, options: { min: 0 } },
        width: 80
      },
      {
        type: 'float',
        name: 'totalUomValue',
        header: i18next.t('field.total_uom_value'),
        width: 120
      },
      {
        type: 'integer',
        name: 'palletQty',
        header: i18next.t('field.pallet_qty'),
        record: { editable: true, options: { min: 0 } },
        width: 80
      },
      ...(this.enableLotIdInput
        ? [
          {
            type: 'string',
            name: 'palletId',
            header: i18next.t('field.lot_id'),
            width: 80
          }
        ]
        : []),
      {
        type: 'date',
        name: 'manufactureDate',
        header: i18next.t('field.manufacture_date'),
        record: { editable: true },
        width: 120
      },
      {
        type: 'string',
        name: 'batchIdRef',
        header: i18next.t('field.batch_no_ref'),
        record: { editable: true },
        width: 150
      },
      {
        type: 'float',
        name: 'unitPrice',
        header: i18next.t('field.unit_price'),
        record: { editable: true },
        width: 80
      },
      {
        type: 'string',
        name: 'remark',
        header: i18next.t('field.remark'),
        record: { editable: true },
        width: 300
      }
    ]

    if (this.enableDirectInbound) {
      const anchor = this.enableLotIdInput ? 'palletId' : 'palletQty'
      insertAfter(addColumns, anchor, [createExpDateColumn()])
      insertAfter(addColumns, 'batchIdRef', [
        createWarehouseColumn(),
        createLocationColumn(rowIndex => this._openAddLocationSelection(rowIndex))
      ])
    }

    this.addProductConfig = {
      pagination: { infinite: true },
      rows: { selectable: { multiple: true } },
      list: {
        fields: addFields
      },
      columns: addColumns
    }

    this.userRole = await this.fetchUserRoleHandler()
  }

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

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

  async _onProductChangeHandler(event) {
    try {
      if (!this.enableDirectInbound) {
        this._checkProductDuplication()
      }

      let changeRecord = event.detail.after
      const changedColumn = event.detail.column.name

      if (event.detail.column.name == 'product') {
        let primaryValue = !!changeRecord.product?.primaryValue
        changeRecord.uomValue = primaryValue ? changeRecord.product.primaryValue : null
        let primaryUnit = !!changeRecord.product?.primaryUnit
        changeRecord.uom = primaryUnit ? changeRecord.product.primaryUnit : ''
        let packingType = !!changeRecord.product?.packingType
        changeRecord.packingType = packingType ? changeRecord.product.packingType : ''
      }

      const amountRelatedColumns = ['uomValue', 'uom', 'packQty']
      if (amountRelatedColumns.indexOf(changedColumn) >= 0) {
        const calcedAmount = await this._calcAmount(changedColumn, changeRecord)
        for (let key in calcedAmount) {
          changeRecord[key] = key == 'packQty' ? Math.ceil(calcedAmount[key]) : calcedAmount[key]
        }
      }

      if (changedColumn === 'unitPrice') {
        let unitPrice = changeRecord.unitPrice
        changeRecord.unitPrice = changeRecord.unitPrice.toFixed(2)
        if (typeof unitPrice === undefined || unitPrice < 0 || isNaN(unitPrice)) {
          throw new Error(i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.unit_price') } }))
        }
      }

      if (changedColumn === 'palletQty') {
        let palletQty = changeRecord.palletQty
        if (typeof palletQty === undefined || palletQty < 0 || isNaN(palletQty)) {
          throw new Error(i18next.t('text.invalid_x', { state: { x: i18next.t('label.pallet_qty') } }))
        }
      }

      if (changedColumn === 'expDate') {
        if (!changeRecord.product?.isRequiredCheckExpiry) {
          delete changeRecord.expDate
          throw new Error(
            i18next.t('text.exp_date_not_required_for_this_product', {
              defaultValue: `Expiry date is not required for this product`
            })
          )
        }
      }
    } catch (e) {
      const beforeValue = event.detail.before && event.detail.before[event.detail.column.name]
      if (beforeValue) {
        event.detail.after[event.detail.column.name] = beforeValue
      } else {
        delete event.detail.after[event.detail.column.name]
      }

      this._showToast(e)
    }
  }

  _calcAmount(changedColumn, changeRecord) {
    let calcedRecord = {}
    let { uomValue, uom, packQty, releaseQty, releaseUomValue } = changeRecord

    if (changedColumn === 'uomValue' && (!uomValue || uomValue < 0))
      throw new Error(i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.uom_value') } }))
    if (changedColumn === 'packQty' && (packQty == null || packQty === '' || packQty < 0 || isNaN(packQty)))
      throw new Error(i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.pack_qty') } }))
    if (changedColumn === 'uom' && !uom)
      throw new Error(i18next.t('text.x_is_empty', { state: { x: i18next.t('label.uom') } }))
    if (uomValue && uom) {
      if (packQty !== 0) calcedRecord.totalUomValue = `${(uomValue * packQty).toFixed(3)} ${uom}`
      if (packQty === 0) calcedRecord.totalUomValue = `0 ${uom}`
    } else {
      calcedRecord.totalUomValue = ''
    }

    if (!this._crossDocking) return calcedRecord

    if (changedColumn === 'releaseQty' || changedColumn === 'releaseUomValue') {
      if (isNaN(releaseQty)) {
        releaseQty = 0
        calcedRecord.releaseQty = releaseQty
      }
      if (isNaN(releaseUomValue)) {
        releaseUomValue = 0
        calcedRecord.releaseUomValue = releaseUomValue
      }

      if (!uomValue)
        throw new Error(i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.uom_value') } }))
      if (packQty === undefined || packQty === null || packQty === '')
        throw new Error(i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.pack_qty') } }))

      if (changedColumn === 'releaseQty') {
        if (typeof releaseQty === undefined || releaseQty < 0) {
          throw new Error(i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.release_qty') } }))
        }
        if (releaseQty > packQty) {
          throw new Error(i18next.t('text.x_exceed_limit', { state: { x: i18next.t('label.release_qty') } }))
        }
        calcedRecord.releaseUomValue = releaseQty * uomValue
      } else {
        if (releaseUomValue === undefined || releaseUomValue < 0) {
          throw new Error(
            i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.release_uom_value') } })
          )
        }

        if (releaseUomValue > packQty * uomValue) {
          throw new Error(i18next.t('text.x_exceed_limit', { state: { x: i18next.t('label.release_uom_value') } }))
        }

        if (releaseUomValue % uomValue) {
          throw new Error(i18next.t('text.invalid_x', { state: { x: i18next.t('label.release_uom_value') } }))
        }

        calcedRecord.releaseQty = releaseUomValue / uomValue
      }
    }

    return calcedRecord
  }

  _checkProductDuplication() {
    let isDuplicated = false
    if (!this.enableLotIdInput) {
      const addedNewRows = this.addProductGrist.dirtyData.records
        .filter(record => record.batchId && record.product && record.product.id && record.packingType)
        .map(record => `${record.batchId}-${record.product.id}-${record.packingType}`)

      addedNewRows.forEach((row, idx, rows) => {
        if (rows.lastIndexOf(row) !== idx) {
          isDuplicated = true
        }
      })

      const existingRows = this.editProductGrist.dirtyData.records
        .filter(record => record.batchId && record.product && record.product.id && record.packingType)
        .map(record => `${record.batchId}-${record.product.id}-${record.packingType}`)

      existingRows.forEach((row, idx, rows) => {
        if (rows.lastIndexOf(row) !== idx) {
          isDuplicated = true
        }
      })

      const matchingRow = addedNewRows.filter(newRow => existingRows.includes(newRow))
      if (matchingRow?.length > 0) isDuplicated = true

      if (isDuplicated) {
        throw new Error(i18next.t('text.duplicated_batch_id'))
      }
    } else if (this.enableLotIdInput) {
      const addedNewRows = this.addProductGrist.dirtyData.records
        .filter(record => record.palletId)
        .map(record => `${record.palletId}`)

      addedNewRows.forEach((row, idx, rows) => {
        if (rows.lastIndexOf(row) !== idx) {
          isDuplicated = true
        }
      })

      const existingRows = this.editProductGrist.dirtyData.records
        .filter(record => record.palletId)
        .map(record => `${record.palletId}`)

      existingRows.forEach((row, idx, rows) => {
        if (rows.lastIndexOf(row) !== idx) {
          isDuplicated = true
        }
      })

      const matchingRow = addedNewRows.filter(newRow => existingRows.includes(newRow))
      if (matchingRow?.length > 0) isDuplicated = true

      if (isDuplicated) {
        throw new Error(i18next.t('text.there_is_duplicated_lot_id'))
      }
    }
  }

  _openLocationSelection(rowIndex) {
    openPopup(
      html`
        <buffer-location-selector
          .bizplaceId="${this._bizplaceId}"
          .data="${this.productData}"
          .enableDirectInbound="${this.enableDirectInbound}"
          @selected="${async e => {
          this.editProductGrist.dirtyData.records[rowIndex].location = { id: e.detail.id, name: e.detail.name }
          this.editProductGrist.dirtyData.records[rowIndex].warehouse = {
            id: e.detail.warehouse.id,
            name: e.detail.warehouse.name
          }
          this.editProductGrist.dirtyData.records[rowIndex].__dirty__ = true

          if (this.editProductGrist.dirtyData.records.length !== rowIndex) {
            // update existing product data records
            this.editProductGrist.dirtyData.records.splice(rowIndex, 1, {
              ...this.editProductGrist.dirtyData.records[rowIndex]
            })

            this.productData = {
              ...this.productData,
              records: [...this.editProductGrist.dirtyData.records]
            }

            this.editProductGrist.data.records = this.editProductGrist.dirtyData.records
          } else {
            this.productData = {
              ...this.productData,
              records: [...this.editProductGrist.dirtyData.records]
            }
          }
        }}"
        ></buffer-location-selector>
      `,
      {
        backdrop: true,
        size: 'large',
        title: i18next.t('title.select_location', 'Select Location')
      }
    )
  }

  _openAddLocationSelection(rowIndex) {
    openPopup(
      html`
        <buffer-location-selector
          .bizplaceId="${this._bizplaceId}"
          .data="${this.newProductData}"
          .enableDirectInbound="${this.enableDirectInbound}"
          @selected="${async e => {
          this.addProductGrist.dirtyData.records[rowIndex].location = { id: e.detail.id, name: e.detail.name }
          this.addProductGrist.dirtyData.records[rowIndex].warehouse = {
            id: e.detail.warehouse.id,
            name: e.detail.warehouse.name
          }
          this.addProductGrist.dirtyData.records[rowIndex].__dirty__ = true

          if (this.addProductGrist.dirtyData.records.length !== rowIndex) {
            // update existing product data records
            this.addProductGrist.dirtyData.records.splice(rowIndex, 1, {
              ...this.addProductGrist.dirtyData.records[rowIndex]
            })

            this.newProductData = {
              ...this.newProductData,
              records: [...this.addProductGrist.dirtyData.records]
            }

            this.addProductGrist.data.records = this.addProductGrist.dirtyData.records
          } else {
            this.newProductData = {
              ...this.newProductData,
              records: [...this.addProductGrist.dirtyData.records]
            }
          }
        }}"
        ></buffer-location-selector>
      `,
      {
        backdrop: true,
        size: 'large',
        title: i18next.t('title.select_location', 'Select Location')
      }
    )
  }

  async pageUpdated(changes, lifecycle) {
    if (this.active) {
      await this.updateComplete

      this.editProductGrist.config = this.editProductConfig
    }
  }

  _openProductSelection(rowIndex) {
    if (this.bizplace?.id) {
      openPopup(
        html`
          <select-product-popup
            .bizplaceId="${this.bizplace.id}"
            @selected="${e => {
            // let newRecord = []
            // newRecord.push(e.detail)

            if (this.addProductGrist.dirtyData.records.length !== rowIndex) {
              // update existing product data records
              this.addProductGrist.dirtyData.records.splice(rowIndex, 1, {
                ...this.addProductGrist.dirtyData.records[rowIndex],
                ...e.detail
              })

              this.newProductData = {
                ...this.newProductData,
                records: [...this.addProductGrist.dirtyData.records]
              }
            } else {
              this.newProductData = {
                ...this.newProductData,
                records: [...this.addProductGrist.dirtyData.records, e.detail]
              }
            }
          }}"
          ></select-product-popup>
        `,
        {
          backdrop: true,
          size: 'large',
          title: i18next.t('title.select_item')
        }
      )
    } else {
      this._showToast({ message: i18next.t('text.company_selection_is_empty') })
    }
  }

  async _addEditProducts(approveAdminAddEditProducts) {
    try {
      if (this.enableDirectInbound) {
        approveAdminAddEditProducts = false
      }

      this._validateProducts()

      let existingOrderProducts = []
      let newOrderProducts = []

      existingOrderProducts = await this._getExistingOrderProducts()
      newOrderProducts = await this._getNewOrderProducts()

      if (existingOrderProducts?.length || newOrderProducts?.length) {
        const result = await CustomAlert({
          title: i18next.t('title.are_you_sure'),
          text: i18next.t('text.edit_add_order_product'),
          confirmButton: { text: i18next.t('button.confirm') },
          cancelButton: { text: i18next.t('button.cancel') }
        })

        if (!result.value) return
        const response = await client.mutate({
          mutation: gql`
            mutation addEditArrivalNoticeProducts(
              $approvedAddEditProducts: Boolean
              $ganNo: String!
              $newOrderProducts: [NewOrderProduct!]
              $existingOrderProducts: [OrderProductPatch!]
            ) {
              addEditArrivalNoticeProducts(
                approvedAddEditProducts: $approvedAddEditProducts
                ganNo: $ganNo
                newOrderProducts: $newOrderProducts
                existingOrderProducts: $existingOrderProducts
              )
            }
          `,
          variables: {
            approvedAddEditProducts: approveAdminAddEditProducts ? true : false,
            ganNo: this.ganNo,
            newOrderProducts,
            existingOrderProducts
          }
        })

        if (!response.errors) {
          if (approveAdminAddEditProducts) {
            this._showToast({ message: i18next.t('text.add_edit_products_has_been_updated') })
          } else {
            this._showToast({ message: i18next.t('text.add_edit_products_has_been_submitted_for_approval') })
          }
          this.dispatchEvent(new CustomEvent('completed'))
          history.back()
        }
      } else {
        this._showToast({ message: i18next.t('text.no_changes_to_be_submitted') })
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  _getNewOrderProducts() {
    const isStatusPending = this.status === 'PENDING' && !this.enableDirectInbound
    return this.addProductGrist.dirtyData.records.map(record => {
      record.unitPrice = parseFloat(record.unitPrice) || 0

      let batchId = record.batchId ? record.batchId.trim() : null
      let batchIdRef = record.batchIdRef ? record.batchIdRef.trim() : null

      return {
        batchId: isStatusPending ? batchId : `N/A`,
        adjustedBatchId: !isStatusPending ? batchId : null,
        palletQty: isStatusPending ? (record.palletQty ? record.palletQty : 0) : 0,
        adjustedPalletQty: !isStatusPending ? (record?.palletQty ? record.palletQty : null) : null,
        palletId: record.palletId ? record.palletId : null,
        product: { id: record.product.id },
        productDetail: { id: record.productDetailId },
        packingType: isStatusPending ? record.packingType : 'N/A',
        adjustedPackingType: !isStatusPending ? record.packingType : null,
        uomValue: isStatusPending ? record.uomValue : 0,
        status: ORDER_PRODUCT_STATUS.ADDED.value,
        adjustedUomValue: !isStatusPending ? (record?.uomValue ? record.uomValue : 0) : null,
        uom: isStatusPending ? record.uom : 'N/A',
        adjustedUom: !isStatusPending ? record.uom : null,
        packQty: isStatusPending ? (record.packQty ? parseFloat(parseFloat(record.packQty).toFixed(3)) : 0) : 0,
        adjustedPackQty: !isStatusPending ? record.packQty : null,
        totalUomValue: isStatusPending ? record.totalUomValue : 'N/A',
        adjustedTotalUomValue: record?.totalUomValue && !isStatusPending ? record.totalUomValue : 'N/A',
        manufactureDate: record?.manufactureDate ? record.manufactureDate : null,
        batchIdRef: isStatusPending ? batchIdRef : 'N/A',
        adjustedBatchIdRef: record?.batchIdRef && !isStatusPending ? batchIdRef : null,
        unitPrice: isStatusPending ? record.unitPrice : 0,
        adjustedUnitPrice: record?.unitPrice && !isStatusPending ? record.unitPrice : null,
        remark: record?.remark ? record.remark : null,
        packingSize: record.packingSize || record.product.packingSize,
        expDate: record?.expDate ? record.expDate : null,
        location: record?.location ? record.location : null,
        warehouse: record?.warehouse ? record.warehouse : null
      }
    })
  }

  _getExistingOrderProducts() {
    let editedOrderProducts = []
    const isStatusPending = this.status === 'PENDING' && !this.enableDirectInbound
    if (this.editProductGrist.dirtyData.records.some(record => record.__dirty__)) {
      this.editProductGrist.dirtyData.records.map(record => {
        record.unitPrice = parseFloat(record.unitPrice)
        let batchId = record.batchId ? record.batchId.trim() : null
        let batchIdRef = record.batchIdRef ? record.batchIdRef.trim() : null

        editedOrderProducts.push({
          id: record.id,
          adjustedBatchId: !isStatusPending
            ? batchId === record.__origin__.batchId
              ? null
              : batchId
            : null,
          adjustedBatchIdRef: !isStatusPending
            ? batchIdRef === record.__origin__.batchIdRef
              ? null
              : batchIdRef
            : null,
          adjustedPalletQty: !isStatusPending
            ? record.palletQty === record.__origin__.palletQty
              ? null
              : record.palletQty
            : null,
          product: { id: record.product.id },
          productDetail: { id: record.productDetail.id },
          adjustedPackingType: !isStatusPending
            ? record.packingType === record.__origin__.packingType
              ? null
              : record.packingType
            : null,
          adjustedUomValue: !isStatusPending
            ? record.uomValue == record.__origin__.uomValue
              ? null
              : record.uomValue
            : null,
          adjustedUom: !isStatusPending ? (record.uom === record.__origin__.uom ? null : record.uom) : null,
          adjustedPackQty: !isStatusPending
            ? record.packQty == record.__origin__.packQty
              ? null
              : record.packQty
            : null,
          adjustedTotalUomValue: !isStatusPending
            ? record.totalUomValue == record.__origin__.totalUomValue
              ? null
              : record.totalUomValue
            : null,
          adjustedExpDate: !isStatusPending
            ? record.expDate == record.__origin__.expDate
              ? null
              : record.expDate
            : null,
          adjustedWarehouse: !isStatusPending
            ? record.warehouse == record.__origin__?.__origin__?.warehouse
              ? null
              : record.warehouse
            : null,
          adjustedLocation: !isStatusPending
            ? record.location == record.__origin__?.__origin__?.location
              ? null
              : record.location
            : null,
          manufactureDate: record?.manufactureDate ? record.manufactureDate : null,
          palletId: record?.palletId ? record.palletId : null,
          adjustedUnitPrice: record?.unitPrice && !isStatusPending ? record.unitPrice : null,
          remark: record?.remark ? record.remark : null,
          ...(isStatusPending && {
            unitPrice: record.unitPrice,
            batchIdRef: batchIdRef,
            packingType: record.packingType,
            packQty: record.packQty,
            palletQty: record.palletQty,
            uomValue: record.uomValue,
            uom: record.uom,
            batchId: batchId,
            totalUomValue: record.totalUomValue,
            expDate: record.__origin__.expDate,
            location: record.__origin__.location,
            warehouse: record.__origin__.warehouse
          })
        })
      })
    }
    return editedOrderProducts
  }

  _validateProducts() {
    if (
      this.addProductGrist.dirtyData.records.length > 0 &&
      this.addProductGrist.dirtyData.records.filter(
        record =>
          !record.batchId ||
          !record.product ||
          !record.packingType ||
          !record.uomValue ||
          !record.uom ||
          !record.packQty
      ).length
    ) {
      throw new Error(i18next.t('text.empty_value_in_add_product_list'))
    }

    this.addProductGrist.dirtyData.records.forEach((record, index) => {
      if (this.enableDirectInbound && record?.product?.isRequiredCheckExpiry && !record.expDate) {
        throw new Error(
          i18next.t('text.exp_date_required_for_product', {
            defaultValue: `Add Product Row ${index + 1}: Expiry date is required for product "${record.product.name}"`,
            product: record.product.name,
            row: index + 1
          })
        )
      }

      if (this.enableDirectInbound && !record.location) {
        throw new Error(
          i18next.t('text.location_required_for_product', {
            defaultValue: `Add Product Row ${index + 1}: Location is missing for product "${record.product.name}"`,
            product: record.product.name,
            row: index + 1
          })
        )
      }
    })

    this.editProductGrist.dirtyData.records.forEach(record => {
      if (record.packQty === 0 && !record.remark) {
        throw new Error(i18next.t('text.remark_is_empty_kindly_fill_in_to_proceed'))
      }
      if (isNaN(record.packQty)) {
        throw new Error(i18next.t('text.pack_qty_is_empty_kindly_fill_in_to_proceed'))
      }
    })
  }

  async fetchUserRoleHandler() {
    const response = await client.query({
      query: gql`
        query myRoles {
          myRoles {
            id
            name
            description
          }
        }
      `
    })

    if (!response.errors?.length) {
      return response.data.myRoles
    }

    return []
  }

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

window.customElements.define('edit-product-popup', EditProductPopup)
