import '@things-factory/form-ui'
import '@things-factory/grist-ui'
import './product-details-popup'
import './product-detail-bizplace-setting-popup'

import gql from 'graphql-tag'
import { css, html } from 'lit-element'
import isEmpty from 'lodash-es/isEmpty'
import isNaN from 'lodash-es/isNaN'
import isNumber from 'lodash-es/isNumber'

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

class ProductList extends localize(i18next)(PageView) {
  static get properties() {
    return {
      searchFields: Array,
      productGristConfig: Object
    }
  }

  static get styles() {
    return [
      ScrollbarStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow: hidden;
        }
        search-form {
          overflow: visible;
        }
        data-grist {
          overflow-y: auto;
          flex: 1;
        }
      `
    ]
  }

  render() {
    return html`
      <search-form .fields=${this.searchFields} @submit=${e => this.dataGrist.fetch()}></search-form>

      <data-grist
        .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
        .config=${this.productGristConfig}
        .data=${this.data}
        .fetchHandler="${this.fetchHandler.bind(this)}"
        @field-change="${this._fieldChange.bind(this)}"
      ></data-grist>
    `
  }

  get context() {
    var actions = [
      {
        title: i18next.t('button.save'),
        action: () => this._saveProducts(this.dataGrist.exportPatchList({ flagName: 'cuFlag' })),
        ...CommonButtonStyles.save
      },
      {
        title: i18next.t('button.restore'),
        action: this._undeleteProducts.bind(this),
        ...CommonButtonStyles.submit
      },
      {
        title: i18next.t('button.delete'),
        action: this._deleteProducts.bind(this),
        ...CommonButtonStyles.delete
      }
    ]

    return {
      title: i18next.t('title.product'),
      actions,
      exportable: {
        name: i18next.t('title.product'),
        data: this._exportableData.bind(this)
      },
      importable: {
        handler: records => {
          const config = {
            rows: this.productGristConfig.rows,
            columns: [
              ...this.productGristConfig.columns.filter(column => column.imex !== undefined),
              {
                type: 'string',
                name: 'childGtin',
                record: { editable: true, align: 'left' },
                header: i18next.t('field.child_gtin'),
                width: 80
              },
              {
                type: 'float',
                name: 'packingSize',
                record: { editable: true, align: 'left' },
                header: i18next.t('field.packing_size'),
                width: 80
              }
            ]
          }
          openImportPopUp(records, config, async patches => {
            await this._importProducts(patches)
            history.back()
          })
        }
      },
      help: 'product/product-list'
    }
  }

  get searchForm() {
    return this.shadowRoot.querySelector('search-form')
  }

  get _bizplaceInput() {
    return this.searchForm.shadowRoot.querySelector('select[name=bizplace]')
  }

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

  async pageUpdated(changes, lifecycle) {
    if (this.active) {
      const productType = await getCodeByName('PRODUCT_TYPES')
      const packingType = await getCodeByName('PACKING_TYPES')
      const uom = await getCodeByName('UOM')
      const weightUnit = await getCodeByName('WEIGHT_UNITS')
      const lengthUnit = await getCodeByName('LENGTH_UNITS')
      this._partners = [...(await this._fetchPartners())].sort(this._compareValues('name', 'asc'))

      this.searchFields = [
        {
          label: i18next.t('field.company'),
          name: 'bizplace',
          type: 'select',
          options: [
            { value: '' },
            ...this._partners.map(partner => {
              return {
                name: `${partner.name} ${partner.description ? `(${partner.description})` : ''}`,
                value: partner.id
              }
            })
          ],
          props: { searchOper: 'eq' }
        },
        {
          label: i18next.t('field.product_info'),
          name: 'product_info',
          props: {
            searchOper: 'i_like'
          }
        },
        {
          label: i18next.t('field.type'),
          name: 'type',
          props: {
            searchOper: 'i_like'
          }
        },
        {
          label: i18next.t('field.deleted'),
          name: 'deleted',
          type: 'checkbox',
          props: { searchOper: 'eq' }
        }
      ]

      this.productGristConfig = {
        pagination: { limit: 50, pages: [20, 50, 100, 500, 999] },
        list: { fields: ['sku', 'name', 'description', 'type', 'packingType'] },
        rows: {
          handlers: { click: this.setProductRefCondition.bind(this) },
          selectable: { multiple: true }
        },
        columns: [
          { type: 'gutter', gutterName: 'dirty' },
          { type: 'gutter', gutterName: 'sequence' },
          { type: 'gutter', gutterName: 'row-selector', multiple: true },
          {
            type: 'gutter',
            gutterName: 'button',
            icon: 'reorder',
            handlers: {
              click: this._showProductDetails.bind(this)
            }
          },
          {
            type: 'gutter',
            gutterName: 'button',
            icon: 'settings',
            handlers: {
              click: this._showProductDetailBizplaceSettings.bind(this)
            }
          },
          {
            type: 'string',
            name: 'sku',
            record: { editable: true },
            imex: { header: '*' + i18next.t('field.sku'), key: 'sku', width: 30, type: 'string' },
            header: '*' + i18next.t('field.sku'),
            sortable: true,
            width: 180
          },
          {
            type: 'string',
            name: 'brandSku',
            record: { editable: true },
            imex: { header: i18next.t('field.brand_sku'), key: 'brandSku', width: 30, type: 'string' },
            header: i18next.t('field.brand_sku'),
            sortable: true,
            width: 180
          },
          {
            type: 'string',
            name: 'name',
            record: { editable: true },
            imex: { header: '*' + i18next.t('field.name'), key: 'name', width: 30, type: 'string' },
            header: '*' + i18next.t('field.name'),
            sortable: true,
            width: 180
          },
          {
            type: 'string',
            name: 'description',
            record: { editable: true },
            imex: { header: i18next.t('field.description'), key: 'description', width: 50, type: 'string' },
            header: i18next.t('field.description'),
            sortable: true,
            width: 300
          },
          {
            type: 'select',
            name: 'type',
            header: '*' + i18next.t('field.type'),
            record: {
              editable: true,
              options: ['', ...Object.keys(productType).map(key => productType[key].name)]
            },
            imex: {
              header: '*' + i18next.t('field.type'),
              key: 'type',
              width: 50,
              type: 'array',
              arrData: productType.map(productType => {
                return {
                  name: productType.name,
                  id: productType.name
                }
              })
            },
            sortable: true,
            width: 120
          },
          {
            type: 'select',
            name: 'packingType',
            header: '*' + i18next.t('field.packing_type'),
            record: {
              editable: true,
              options: ['', ...Object.keys(packingType).map(key => packingType[key].name)]
            },
            imex: {
              header: '*' + i18next.t('field.packing_type'),
              key: 'packingType',
              width: 50,
              type: 'array',
              arrData: packingType.map(packingType => {
                return {
                  name: packingType.name,
                  id: packingType.name
                }
              })
            },
            width: 120
          },
          {
            type: 'select',
            name: 'uom',
            record: {
              editable: true,
              options: ['', ...Object.keys(uom).map(key => uom[key].name)]
            },
            imex: {
              header: '*' + i18next.t('field.uom'),
              key: 'uom',
              width: 10,
              type: 'array',
              arrData: uom.map(uom => {
                return {
                  name: uom.name,
                  id: uom.name
                }
              })
            },
            header: '*' + i18next.t('field.uom'),
            width: 80
          },
          {
            type: 'float',
            name: 'uomValue',
            record: { editable: true, options: { min: 0 } },
            imex: { header: '*' + i18next.t('field.uom_value'), key: 'uomValue', width: 15, type: 'float' },
            header: '*' + i18next.t('field.uom_value'),
            width: 100
          },
          {
            type: 'string',
            name: 'brand',
            record: { editable: true },
            imex: { header: i18next.t('field.brand'), key: 'brand', width: 40, type: 'string' },
            header: i18next.t('field.brand'),
            sortable: true,
            width: 200
          },
          {
            type: 'string',
            name: 'subBrand',
            record: { editable: true },
            imex: { header: i18next.t('field.sub_brand'), key: 'subBrand', width: 30, type: 'string' },
            header: i18next.t('field.sub_brand'),
            sortable: true,
            width: 200
          },
          {
            type: 'string',
            name: 'inventoryAccountCode',
            header: i18next.t('field.inventory_account_code'),
            record: { editable: true },
            imex: {
              header: i18next.t('field.inventory_account_code'),
              key: 'inventoryAccountCode',
              width: 30,
              type: 'string'
            },
            width: 180
          },
          {
            type: 'string',
            name: 'cogsAccountCode',
            header: i18next.t('field.cogs_account_code'),
            record: { editable: true },
            imex: { header: i18next.t('field.cogs_account_code'), key: 'cogsAccountCode', width: 30, type: 'string' },
            width: 160
          },
          {
            type: 'float',
            name: 'bufferQty',
            record: { editable: true, align: 'left', options: { min: 0 } },
            imex: { header: i18next.t('field.buffer_qty'), key: 'bufferQty', width: 20, type: 'float' },
            header: i18next.t('field.buffer_qty'),
            width: 80
          },
          {
            type: 'float',
            name: 'minQty',
            record: { editable: true, align: 'left', options: { min: 0 } },
            imex: { header: i18next.t('field.min_qty'), key: 'minQty', width: 20, type: 'float' },
            header: i18next.t('field.min_qty'),
            width: 80
          },
          {
            type: 'float',
            name: 'maxQty',
            record: { editable: true, align: 'left', options: { min: 0 } },
            imex: { header: i18next.t('field.max_qty'), key: 'maxQty', width: 20, type: 'float' },
            header: i18next.t('field.max_qty'),
            width: 80
          },
          {
            type: 'integer',
            name: 'minInboundShelfLife',
            record: { editable: true },
            imex: { header: i18next.t('field.expiration_period'), key: 'minInboundShelfLife', width: 30, type: 'integer' },
            header: i18next.t('field.expiration_period'),
            sortable: true,
            width: 140
          },
          {
            type: 'object',
            name: 'productRef',
            record: {
              editable: true,
              options: {
                queryName: 'productsByBizplace',
                nameField: 'name',
                descriptionField: 'description',
                select: [
                  { name: 'id', hidden: true },
                  { name: 'sku', header: i18next.t('field.sku') },
                  { name: 'name', header: i18next.t('field.name') },
                  { name: 'description', header: i18next.t('field.description') },
                  { name: 'packingType', header: i18next.t('field.packing_type') },
                  { name: 'uom', header: i18next.t('field.uom') },
                  { name: 'uomValue', header: i18next.t('field.uom_value') }
                ],
                list: { fields: ['sku', 'name', 'description', 'packingType'] }
              }
            },
            imex: {
              header: i18next.t('field.product_ref'),
              key: 'productRef.name',
              width: 30,
              type: 'array',
              arrData: []
            },
            header: i18next.t('field.product_ref'),
            sortable: true,
            width: 230
          },
          {
            type: 'string',
            name: 'gtin',
            record: { editable: true },
            imex: { header: '*' + i18next.t('field.gtin'), key: 'gtin', width: 20, type: 'string' },
            header: '*' + i18next.t('field.gtin'),
            width: 80
          },
          {
            type: 'string',
            name: 'refCode',
            record: { editable: true },
            imex: { header: i18next.t('field.ref_code'), key: 'refCode', width: 20, type: 'string' },
            header: i18next.t('field.ref_code'),
            width: 80
          },
          {
            type: 'select',
            name: 'weightUnit',
            record: {
              editable: true,
              options: ['', ...Object.keys(weightUnit).map(key => weightUnit[key].name)]
            },
            imex: {
              header: '*' + i18next.t('field.weight_unit'),
              key: 'weightUnit',
              width: 20,
              type: 'array',
              arrData: weightUnit.map(weightUnit => {
                return {
                  name: weightUnit.name,
                  id: weightUnit.name
                }
              })
            },
            header: '*' + i18next.t('field.weight_unit'),
            width: 100
          },
          {
            type: 'float',
            name: 'grossWeight',
            record: { editable: true },
            imex: { header: '*' + i18next.t('field.gross_weight'), key: 'grossWeight', width: 20, type: 'float' },
            header: '*' + i18next.t('field.gross_weight'),
            width: 100
          },
          {
            type: 'float',
            name: 'nettWeight',
            record: { editable: true },
            imex: { header: '*' + i18next.t('field.nett_weight'), key: 'nettWeight', width: 20, type: 'float' },
            header: '*' + i18next.t('field.nett_weight'),
            width: 100
          },
          {
            type: 'float',
            name: 'density',
            record: { editable: true },
            imex: { header: i18next.t('field.density'), key: 'density', width: 10, type: 'float' },
            header: i18next.t('field.density'),
            width: 80
          },
          {
            type: 'string',
            name: 'lengthUnit',
            record: {
              editable: true,
              options: ['', ...Object.keys(lengthUnit).map(key => lengthUnit[key].name)]
            },
            imex: {
              header: '*' + i18next.t('field.length_unit'),
              key: 'lengthUnit',
              width: 20,
              type: 'array',
              arrData: lengthUnit.map(lengthUnit => {
                return {
                  name: lengthUnit.name,
                  id: lengthUnit.name
                }
              })
            },
            header: '*' + i18next.t('field.length_unit'),
            width: 100
          },
          {
            type: 'float',
            name: 'width',
            record: { editable: true },
            imex: { header: '*' + i18next.t('field.width'), key: 'width', width: 15, type: 'float' },
            header: '*' + i18next.t('field.width'),
            width: 80
          },
          {
            type: 'float',
            name: 'depth',
            record: { editable: true },
            imex: { header: '*' + i18next.t('field.depth'), key: 'depth', width: 15, type: 'float' },
            header: '*' + i18next.t('field.depth'),
            width: 80
          },
          {
            type: 'float',
            name: 'height',
            record: { editable: true },
            imex: { header: '*' + i18next.t('field.height'), key: 'height', width: 15, type: 'float' },
            header: '*' + i18next.t('field.height'),
            width: 80
          },
          {
            type: 'float',
            name: 'volume',
            record: { editable: true },
            imex: { header: '*' + i18next.t('field.volume'), key: 'volume', width: 15, type: 'float' },
            header: '*' + i18next.t('field.volume'),
            width: 80
          },
          {
            type: 'float',
            name: 'volumeSize',
            record: { editable: true },
            imex: { header: i18next.t('field.volume_size'), key: 'volumeSize', width: 20, type: 'float' },
            header: i18next.t('field.volume_size'),
            width: 100
          },
          {
            type: 'string',
            name: 'auxUnit1',
            record: { editable: true },
            imex: { header: `${i18next.t('field.aux_unit')} 1`, key: 'auxUnit1', width: 20, type: 'string' },
            header: `${i18next.t('field.aux_unit')} 1`,
            width: 100
          },
          {
            type: 'string',
            name: 'auxValue1',
            record: { editable: true },
            imex: { header: `${i18next.t('field.aux_value')} 1`, key: 'auxValue1', width: 20, type: 'string' },
            header: `${i18next.t('field.aux_value')} 1`,
            width: 100
          },
          {
            type: 'string',
            name: 'auxUnit2',
            record: { editable: true },
            imex: { header: `${i18next.t('field.aux_unit')} 2`, key: 'auxUnit2', width: 20, type: 'string' },
            header: `${i18next.t('field.aux_unit')} 2`,
            width: 100
          },
          {
            type: 'string',
            name: 'auxValue2',
            record: { editable: true },
            imex: { header: `${i18next.t('field.aux_value')} 2`, key: 'auxValue2', width: 20, type: 'string' },
            header: `${i18next.t('field.aux_value')} 2`,
            width: 100
          },
          {
            type: 'string',
            name: 'auxUnit3',
            record: { editable: true },
            imex: { header: `${i18next.t('field.aux_unit')} 3`, key: 'auxUnit3', width: 20, type: 'string' },
            header: `${i18next.t('field.aux_unit')} 3`,
            width: 100
          },
          {
            type: 'string',
            name: 'auxValue3',
            record: { editable: true },
            imex: { header: `${i18next.t('field.aux_value')} 3`, key: 'auxValue3', width: 20, type: 'string' },
            header: `${i18next.t('field.aux_value')} 3`,
            width: 100
          },
          {
            type: 'string',
            name: 'auxUnit4',
            record: { editable: true },
            imex: { header: `${i18next.t('field.aux_unit')} 4`, key: 'auxUnit4', width: 20, type: 'string' },
            header: `${i18next.t('field.aux_unit')} 4`,
            width: 100
          },
          {
            type: 'string',
            name: 'auxValue4',
            record: { editable: true },
            imex: { header: `${i18next.t('field.aux_value')} 4`, key: 'auxValue4', width: 20, type: 'string' },
            header: `${i18next.t('field.aux_value')} 4`,
            width: 100
          },
          {
            type: 'string',
            name: 'auxUnit5',
            record: { editable: true },
            imex: { header: `${i18next.t('field.aux_unit')} 5`, key: 'auxUnit5', width: 20, type: 'string' },
            header: `${i18next.t('field.aux_unit')} 5`,
            width: 100
          },
          {
            type: 'string',
            name: 'auxValue5',
            record: { editable: true },
            imex: { header: `${i18next.t('field.aux_value')} 5`, key: 'auxValue5', width: 20, type: 'string' },
            header: `${i18next.t('field.aux_value')} 5`,
            width: 100
          },
          {
            type: 'object',
            name: 'updater',
            header: i18next.t('field.updater'),
            width: 180
          },
          {
            type: 'datetime',
            name: 'updatedAt',
            header: i18next.t('field.updated_at'),
            sortable: true,
            width: 180
          }
        ]
      }

      await this.dataGrist.fetch()
    }
  }

  async fetchHandler({ page, limit, sorters }) {
    const filters = await this.searchForm.getQueryFilters()
    return await this.getMyProducts({ page, limit, sorters, filters })
  }

  async getMyProducts({ page, limit, sorters = [{ name: 'sku' }], filters = [] }) {
    const pagination = { page, limit }
    const sortings = sorters

    const response = await client.query({
      query: gql`
        query productsByBizplace($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
          productsByBizplace(filters: $filters, pagination: $pagination, sortings: $sortings) {
            items {
              sku
              id
              name
              description
              productRef {
                sku
                name
                description
              }
              parentProductRef {
                sku
                name
                description
              }
              refCode
              bundleQty
              packingType
              type
              inventoryAccountCode
              cogsAccountCode
              minInboundShelfLife
              weightUnit
              nettWeight
              grossWeight
              density
              lengthUnit
              volume
              width
              depth
              height
              volumeSize
              uom
              uomValue
              costPrice
              afterTaxCostPrice
              sellPrice
              afterTaxSalesPrice
              mrpPrice
              bufferQty
              minQty
              maxQty
              auxUnit1
              auxValue1
              auxUnit2
              auxValue2
              auxUnit3
              auxValue3
              auxUnit4
              auxValue4
              auxUnit5
              auxValue5
              brandSku
              brand
              subBrand
              gtin
              updater {
                name
                description
              }
              updatedAt
            }
            total
          }
        }
      `,
      variables: { filters, pagination, sortings },
      context: gqlContext()
    })

    if (!response.errors) {
      return {
        total: response.data.productsByBizplace.total || 0,
        records:
          response.data.productsByBizplace.items.map(itm => {
            return {
              ...itm,
              productRef: { name: itm?.productRef ? '(' + itm.productRef.sku + ') ' + itm.productRef.name : '' }
            }
          }) || []
      }
    }
  }

  _showProductDetails(columns, data, column, record, rowIndex) {
    if (record.id) {
      openPopup(
        html`
          <product-details-popup
            .productId="${record.id}"
            @saved="${e => {
              this.dataGrist.fetch()
            }}"
          ></product-details-popup>
        `,
        {
          backdrop: true,
          size: 'large',
          title: `${record.sku}`
        }
      )
    }
  }

  _showProductDetailBizplaceSettings(columns, data, column, record, rowIndex) {
    if (record.id) {
      openPopup(
        html`
          <product-detail-bizplace-setting-popup
            .productId="${record.id}"
            @saved="${e => {
              this.dataGrist.fetch()
            }}"
          ></product-detail-bizplace-setting-popup>
        `,
        {
          backdrop: true,
          size: 'large',
          title: `Warehouse Product Settings(${record.sku})`
        }
      )
    }
  }

  setProductRefCondition(_columns, _data, _column, record, _rowIndex) {
    this.productGristConfig.columns.map(column => {
      if (column.name === 'productRef') {
        if (record && record.id) {
          column.record.options.basicArgs = { filters: [{ name: 'id', operator: 'noteq', value: record.id }] }
        } else {
          delete column.record.options.basicArgs
        }
      }
    })
  }

  _fieldChange(e) {
    var { after, before, column, record, row } = e.detail

    switch (column.name) {
      case 'gtin':
        if (after == '') {
          this.dataGrist._data.records[row].gtin = before

          this.data = {
            ...this.dataGrist._data
          }

          this.showToast('GTIN is required')
        }

        break
      default:
        break
    }

    if (column.record?.options?.min > after) {
      this.dataGrist._data.records[row][column.name] = before
      this.data = {
        ...this.dataGrist._data
      }
      this.showToast(`Minimum value of ${column.record.options.min} is required.`)
    }
  }

  async _saveProducts(patches) {
    try {
      if (isEmpty(this._bizplaceInput.value) || this._bizplaceInput?.value == undefined) {
        return this.showToast(i18next.t('text.no_company_selected'))
      }

      if (!patches?.length) {
        return this.showToast(i18next.t('text.nothing_changed'))
      }

      patches = patches.map(patch => {
        return {
          ...patch,
          minInboundShelfLife: patch?.minInboundShelfLife ? parseInt(patch.minInboundShelfLife) : undefined,
          productRef: patch.productRef?.id ? { id: patch.productRef?.id } : undefined,
          parentProductRef: patch.parentProductRef?.id ? { id: patch.parentProductRef?.id } : undefined,
          bizplace: { id: this._bizplaceInput.value }
        }
      })

      this._validate(this.dataGrist.dirtyRecords)

      const response = await client.mutate({
        mutation: gql`
          mutation updateMultipleProduct($patches: [ProductPatch]!) {
            updateMultipleProduct(patches: $patches) {
              name
            }
          }
        `,
        variables: { patches },
        context: gqlContext()
      })

      if (!response.errors) {
        this.showToast(i18next.t('text.data_updated_successfully'))
        this.dataGrist.fetch()
      }
    } catch (error) {
      this.showToast(error)
    }
  }

  async _importProducts(patches) {
    try {
      if (!patches?.length) {
        return this.showToast(i18next.t('text.nothing_changed'))
      }

      patches = patches.map(patch => {
        return {
          ...patch,
          minInboundShelfLife: patch?.minInboundShelfLife ? parseInt(patch.minInboundShelfLife) : undefined,
          productRef: patch.productRef?.id ? { id: patch.productRef?.id } : undefined,
          bizplace: { id: this._bizplaceInput.value }
        }
      })

      this._validate(patches)

      const response = await client.mutate({
        mutation: gql`
          mutation importMultipleProduct($patches: [ProductPatch]!) {
            importMultipleProduct(patches: $patches) {
              name
            }
          }
        `,
        variables: { patches },
        context: gqlContext()
      })

      if (!response.errors) {
        this.showToast(i18next.t('text.data_import_successfully'))
        this.dataGrist.fetch()
      }
    } catch (error) {
      this.showToast(error)
    }
  }

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

    if (!response.errors) {
      return response.data.permittedPartnersCompanyBizplaces.items
    }
  }

  _compareValues(key, order = 'asc') {
    return function innerSort(a, b) {
      if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
        return 0
      }

      const varA = typeof a[key] === 'string' ? a[key].toUpperCase() : a[key]
      const varB = typeof b[key] === 'string' ? b[key].toUpperCase() : b[key]

      let comparison = 0
      if (varA > varB) {
        comparison = 1
      } else if (varA < varB) {
        comparison = -1
      }
      return order === 'desc' ? comparison * -1 : comparison
    }
  }

  _validate(data) {
    let errors = []
    data = data.map(itm => {
      if (isEmpty(itm.sku) || '') {
        if (!errors.find(err => err.type == 'sku')) errors.push({ type: 'sku', value: 'Product SKU is required' })
      }
      if (isEmpty(itm.name) || '') {
        if (!errors.find(err => err.type == 'name')) errors.push({ type: 'name', value: 'Product name is required' })
      }
      if (isEmpty(itm.type) || '') {
        if (!errors.find(err => err.type == 'type')) errors.push({ type: 'name', value: 'Product type is required' })
      }
      if (isEmpty(itm.packingType) || '') {
        if (!errors.find(err => err.type == 'packingType'))
          errors.push({ type: 'packingType', value: 'Packing type is required' })
      }
      if (isEmpty(itm.uom) || '') {
        if (!errors.find(err => err.type == 'uom')) errors.push({ type: 'uom', value: 'UOM is required' })
      }
      if (!isNumber(itm.uomValue) || isNaN(itm.uomValue) || '' || itm?.uomValue <= 0) {
        if (!errors.find(err => err.type == 'uomValue'))
          errors.push({ type: 'uomValue', value: 'UOM Value is required' })
      }
      return itm
    })

    if (errors.length > 0) {
      throw new Error(errors.map(itm => itm.value).join(', '))
    }
  }

  async _deleteProducts() {
    const ids = this.dataGrist.selected.map(record => record.id)

    if (!ids?.length) {
      return this.showToast(i18next.t('text.there_is_nothing_to_delete'))
    }

    const anwer = await CustomAlert({
      type: 'warning',
      title: i18next.t('button.delete'),
      text: i18next.t('text.are_you_sure'),
      confirmButton: { text: i18next.t('button.delete') },
      cancelButton: { text: i18next.t('button.cancel') }
    })

    if (!anwer.value) return

    const response = await client.mutate({
      mutation: gql`
        mutation deleteProducts($ids: [String]!) {
          deleteProducts(ids: $ids)
        }
      `,
      variables: { ids },
      context: gqlContext()
    })

    if (!response.errors) {
      CustomAlert({
        type: 'success',
        title: i18next.t('text.completed'),
        text: i18next.t('text.data_deleted_successfully'),
        confirmButton: { text: i18next.t('button.confirm') }
      })
      this.dataGrist.fetch()
    }
  }

  async _undeleteProducts() {
    const ids = this.dataGrist.selected.map(record => record.id)

    if (!ids?.length) {
      return this.showToast(i18next.t('text.there_is_nothing_to_restore'))
    }

    const anwer = await CustomAlert({
      type: 'warning',
      title: i18next.t('button.restore'),
      text: i18next.t('text.are_you_sure'),
      confirmButton: { text: i18next.t('button.restore') },
      cancelButton: { text: i18next.t('button.cancel') }
    })

    if (!anwer.value) return

    const response = await client.mutate({
      mutation: gql`
        mutation undeleteProducts($ids: [String]!) {
          undeleteProducts(ids: $ids)
        }
      `,
      variables: { ids },
      context: gqlContext()
    })

    if (!response.errors) {
      CustomAlert({
        type: 'success',
        title: i18next.t('text.completed'),
        text: i18next.t('text.data_restore_successfully'),
        confirmButton: { text: i18next.t('button.confirm') }
      })
      this.dataGrist.fetch()
    }
  }

  async _exportableData() {
    let records = []

    if (this.dataGrist.selected && this.dataGrist.selected.length > 0) {
      records = this.dataGrist.selected
    } else {
      records = (await this.getMyProducts({ page: 0, limit: 999999 })).records || []
    }

    var headerSetting = this.dataGrist._config.columns
      .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
      .map(column => {
        if (column.imex.key == 'productRef.name') {
          column.imex.arrData = records.map(product => {
            return {
              name: '(' + product.sku + ') ' + product.name,
              id: product.id
            }
          })
        }
        return column.imex
      })

    headerSetting.push({ header: `${i18next.t('field.child_gtin')}`, key: 'childGtin', width: 20, type: 'string' })
    headerSetting.push({ header: `${i18next.t('field.packing_size')}`, key: 'packingSize', width: 20, type: 'float' })

    var data = records.map(item => {
      return {
        id: '',
        ...this.productGristConfig.columns
          .filter(column => column.type !== 'gutter' && column.record !== undefined && column.imex !== undefined)
          .reduce((record, column) => {
            record[column.imex.key] = column.imex.key
              .split('.')
              .reduce((obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : undefined), item)
            return record
          }, {})
      }
    })

    return { header: headerSetting, data: data }
  }

  showToast(message) {
    document.dispatchEvent(new CustomEvent('notify', { detail: { message, option: { timer: 1000 } } }))
  }
}

window.customElements.define('product-list', ProductList)
