import '@things-factory/barcode-ui'
import '@things-factory/grist-ui'
import './inventory-assign-popup'
import './inventory-auto-assign-popup'
import './select-operator-popup'
import './inventory-reassign-popup'
import './item-label-popup'

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

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, navigate, PageView } from '@things-factory/shell'
import { CommonButtonStyles } from '@things-factory/styles'
import { isMobileDevice } from '@things-factory/utils'

import { fetchSettingRule } from '../../fetch-setting-value'
import { ORDER_INVENTORY_STATUS, WORKSHEET_STATUS } from '../constants'

class WorksheetBatchPicking extends localize(i18next)(PageView) {
  static get properties() {
    return {
      isPalletPickingOrder: Boolean,
      _worksheetId: String,
      _worksheetNo: String,
      _taskNo: String,
      _worksheetStatus: String,
      _loading: Boolean,
      assignee: Object,
      productGristConfig: Object,
      wsdGristConfig: Object,
      productGristData: Object,
      worksheetDetailData: Object,
      releaseGoodNoRows: Number,
      isRecall: Boolean,
      isAssignedInventory: Boolean,
      _worksheetPickingAssignment: Boolean
    }
  }

  static get styles() {
    return [
      MultiColumnFormStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow-x: auto;
        }
        .form-container {
          display: flex;
        }
        .form-container > form {
          flex: 1;
        }
        barcode-tag {
          width: 100px;
          height: 100px;
          margin: 10px;
        }
        .grist {
          background-color: var(--main-section-background-color);
          display: flex;
          flex-direction: row;
          flex: 1;
          overflow-y: auto;
        }
        .grist-column {
          flex: 1;
          display: flex;
          flex-direction: column;
          overflow: auto;
        }
        data-grist {
          overflow-y: hidden;
          flex: 1;
        }
        h2 {
          padding: var(--subtitle-padding);
          font: var(--subtitle-font);
          color: var(--subtitle-text-color);
          border-bottom: var(--subtitle-border-bottom);
        }
        .grist h2 {
          margin: var(--grist-title-margin);
          border: var(--grist-title-border);
          font: var(--grist-title-font);
          color: var(--secondary-color);
        }

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

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

  constructor() {
    super()
    this.releaseGoodNoRows = 1
    this.isPalletPickingOrder = false
    this.worksheetDetailData = { records: [] }
    this._loading = false
  }

  get context() {
    var actions = [
      {
        title: i18next.t('button.back'),
        action: () => navigate('merged_outbound_worksheets'),
        ...CommonButtonStyles.back
      }
    ]

    if (this._printItemLabel) {
      actions.push({
        title: i18next.t('button.print_label'),
        action: this._openItemLabelPrintPopup.bind(this),
        ...CommonButtonStyles.label
      })
    }

    if (this.undoable) {
      actions.push({
        title: i18next.t('button.undo'),
        action: this._undoAssignment.bind(this),
        ...CommonButtonStyles.undo
      })
    }

    if (this.activatable || this.assignable) {
      actions.push({
        title: i18next.t('button.select_operator'),
        action: this._selectOperator.bind(this),
        ...CommonButtonStyles.add
      })
    }

    if (this.activatable) {
      if (this.isAssignedInventory) {
        actions.push({
          title: i18next.t('button.reassign'),
          action: this._openReassignInventoryPopup.bind(this),
          ...CommonButtonStyles.assignment
        })
      }

      actions.push({
        title: i18next.t('button.activate'),
        action: this._activateWorksheet.bind(this),
        ...CommonButtonStyles.activate
      })
    }

    if (
      !this.activatable &&
      (this.worksheetDetailData?.records.find(itm => itm.obsolete == true) ||
        (this._worksheetPickingAssignment && this.worksheetDetailData?.records.find(itm => itm.status == 'PICKING')))
    ) {
      actions.push({
        title: i18next.t('button.reassign'),
        action: this._openReassignInventoryPopup.bind(this),
        ...CommonButtonStyles.assignment
      })
    }

    if (this.assignable && !this._worksheetPickingAssignment) {
      actions.push({
        title: i18next.t('button.auto_assign'),
        action: this._showAutoAssignPopup.bind(this),
        ...CommonButtonStyles.assignment
      })
    }

    return {
      title: i18next.t('title.worksheet_batch_picking'),
      actions,
      printable: {
        accept: ['preview'],
        content: this
      },
      help: 'operato-wms/outbound/worksheet-batch-picking'
    }
  }

  render() {
    return html`
      <div class="form-container">
        <form class="multi-column-form">
          <fieldset>
            <legend>${i18next.t('title.batch_picking')}</legend>
            <label>${i18next.t('label.worksheet_no')}</label>
            <input name="name" readonly />

            <label>${i18next.t('label.task_no')}</label>
            <input name="taskNo" readonly />

            <label>${i18next.t('label.company')}</label>
            <input name="bizplace" readonly />

            <label>${i18next.t('label.picker')}</label>
            <input name="assignee" readonly />

            <label>${i18next.t('label.status')}</label>
            <select name="status" disabled>
              ${Object.keys(WORKSHEET_STATUS).map(
                key => html`<option value="${WORKSHEET_STATUS[key].value}">${WORKSHEET_STATUS[key].name}</option>`
              )}
            </select>

            <label>${i18next.t('label.release_good_no')}</label>
            <textarea name="releaseGoodNo" rows="5" readonly></textarea>
          </fieldset>
        </form>

        <barcode-tag bcid="qrcode" .value=${this._taskNo} showLogo="true"></barcode-tag>
      </div>

      <div class="grist">
        ${this._worksheetStatus === WORKSHEET_STATUS.DEACTIVATED.value && !this.isPalletPickingOrder
          ? html`
              <div class="grist-column">
                <h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.product')}</h2>

                <data-grist
                  id="product-grist"
                  .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
                  .config=${this.productGristConfig}
                  .data="${this.productGristData}"
                ></data-grist>
              </div>
            `
          : ''}
        ${this._worksheetStatus == WORKSHEET_STATUS.DEACTIVATED.value &&
        this._worksheetPickingAssignment &&
        this.worksheetDetailData.records.length == 0
          ? ''
          : html`
              <div class="grist-column">
                <h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.worksheet_detail')}</h2>
                <data-grist
                  id="wsd-grist"
                  .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
                  .config=${this.wsdGristConfig}
                  .data="${this.worksheetDetailData}"
                ></data-grist>
              </div>
            `}
      </div>
    `
  }

  async pageUpdated(changes) {
    if (this.active && (changes.resourceId || this._worksheetNo)) {
      this._spinner(true)
      if (changes.resourceId) {
        this._worksheetNo = changes.resourceId
      }
      this._clearAll()
      await this.fetchOrderInventories()
      this._spinner(false)
      this.updateContext()
      this._updateGristConfig()
    }
  }

  async pageInitialized() {
    this._worksheetPickingAssignment = await fetchSettingRule('enable-worksheet-picking-activation-assignment')
    this._printItemLabel = await fetchSettingRule('enable-item-label')

    this.productGristConfig = {
      pagination: { infinite: true },
      rows: {
        appendable: false,
        classifier: record => {
          return {
            emphasized: record.completed
          }
        },
        handlers: {
          click: async (columns, data, column, record, rowIndex) => {
            if (record.batchId && record.product?.name && record.packingType) {
              await this.fetchWorksheetDetails(
                this._worksheetNo,
                record.batchId,
                record.product.name,
                record.product.sku,
                record.packingType,
                record.packingSize
              )
              this._selectedProduct = {
                batchId: record.batchId,
                product: record.product,
                packingType: record.packingType,
                packingSize: record.packingSize,
                uom: record.uom,
                releaseQty: record.releaseQty,
                releaseUomValue: record.releaseUomValue,
                completed: record.completed,
                orderProductId: record.orderProduct.id
              }

              this.updateContext()
            }
          }
        }
      },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'boolean',
          name: 'completed',
          header: i18next.t('field.done'),
          width: 40
        },
        {
          type: 'gutter',
          gutterName: 'button',
          icon: 'assignment',
          handlers: {
            click: (columns, data, column, record, rowIndex) => {
              if (record.completed) return
              if (this._worksheetPickingAssignment) return

              this._selectedProduct = {
                batchId: record.batchId,
                product: record.product,
                bizplaceId: record.bizplace.id,
                packingType: record.packingType,
                packingSize: record.packingSize,
                uom: record.uom,
                releaseQty: record.releaseQty,
                releaseUomValue: record.releaseUomValue,
                orderProductId: record.orderProduct.id
              }
              this._showInventoryAssignPopup()
            }
          }
        },
        {
          type: 'string',
          name: 'batchId',
          header: i18next.t('field.batch_id'),
          width: 100
        },
        {
          type: 'string',
          name: 'sku',
          header: i18next.t('field.sku'),
          width: 100
        },
        {
          type: 'object',
          name: 'product',
          header: i18next.t('field.product'),
          width: 250
        },
        {
          type: 'string',
          name: 'packingType',
          header: i18next.t('field.packing_type'),
          width: 150
        },
        {
          type: 'number',
          name: 'packingSize',
          header: i18next.t('field.packing_size'),
          width: 140
        },
        {
          type: 'float',
          name: 'releaseQty',
          header: i18next.t('field.release_qty'),
          width: 60
        },
        {
          type: 'float',
          name: 'releaseUomValue',
          header: i18next.t('field.release_uom_value'),
          width: 60
        },
        {
          type: 'boolean',
          name: 'obsolete',
          header: i18next.t('field.obsolete'),
          width: 60
        }
      ]
    }

    this.preWsdGristConfig = {
      list: {
        fields: [
          'palletId',
          'cartonId',
          'batchId',
          'sku',
          'product',
          'packingType',
          'packingSize',
          'location',
          'releaseQty',
          'batchIdRef',
          'status'
        ]
      },
      pagination: { infinite: true },
      rows: { appendable: false },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'string',
          name: 'batchId',
          header: i18next.t('field.batch_id'),
          width: 100
        },
        {
          type: 'string',
          name: 'palletId',
          header: i18next.t('field.lot_id'),
          width: 120
        },
        {
          type: 'string',
          name: 'cartonId',
          header: i18next.t('field.carton_id'),
          width: 120
        },
        {
          type: 'string',
          name: 'sku',
          header: i18next.t('field.sku'),
          width: 100
        },
        {
          type: 'object',
          name: 'product',
          header: i18next.t('field.product'),
          width: 250
        },
        {
          type: 'string',
          name: 'packingType',
          header: i18next.t('field.packing_type'),
          width: 150
        },
        {
          type: 'number',
          name: 'packingSize',
          header: i18next.t('field.packing_size'),
          width: 140
        },
        {
          type: 'object',
          name: 'location',
          header: i18next.t('field.location'),
          width: 120
        },
        {
          type: 'float',
          name: 'releaseQty',
          header: i18next.t('field.release_qty'),
          width: 60
        },
        {
          type: 'string',
          name: 'releaseUomValueWithUom',
          header: i18next.t('field.release_uom_value'),
          width: 60
        }
      ]
    }
  }

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

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

  get operatorInput() {
    return this.renderRoot.querySelector('input[name=assignee]')
  }

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

  get undoable() {
    return this.productGristData?.records.some(record => record?.completed) && this._selectedProduct?.completed
  }

  get activatable() {
    if (this.productGristData?.records.every(record => record.completed)) {
      let foundObsoleteItems = this.worksheetDetailData?.records.find(itm => itm.obsolete == true)
      return this._worksheetStatus === WORKSHEET_STATUS.DEACTIVATED.value && (!foundObsoleteItems || this.isRecall)
    } else {
      return this._worksheetStatus === WORKSHEET_STATUS.DEACTIVATED.value && this._worksheetPickingAssignment
    }
  }

  get assignable() {
    return !this.productGristData?.records.every(record => record.completed)
  }

  async fetchOrderInventories() {
    this._loading = true
    if (!this._worksheetNo) return

    try {
      const response = await client.query({
        query: gql`
          query worksheet($name: String!) {
            worksheet(name: $name) {
              id
              name
              status
              type
              taskNo
              assignee {
                id
                name
              }
              bizplace {
                name
              }
              orderInventories {
                id
                status
                batchId
                product {
                  id
                  name
                  sku
                  description
                  pickingStrategy
                }
                bizplace {
                  id
                }
                orderProduct {
                  id
                  name
                }
                packingType
                packingSize
                uom
                releaseQty
                releaseUomValue
                inventory {
                  qty
                  lockedQty
                  palletId
                  cartonId
                  uom
                  obsolete
                  location {
                    name
                    description
                  }
                }
                releaseGood {
                  id
                  name
                  recall
                }
              }
              worksheetDetails {
                status
                targetInventory {
                  batchId
                  product {
                    id
                    name
                    sku
                    description
                    pickingStrategy
                  }
                  bizplace {
                    id
                  }
                  packingType
                  packingSize
                  releaseQty
                  releaseUomValue
                  status
                  inventory {
                    product {
                      name
                      sku
                      description
                    }
                  }
                  releaseGood {
                    id
                    name
                    refNo
                    attentionTo
                    attentionCompany
                    releaseDate
                    city
                  }
                }
                targetProduct {
                  batchId
                  product {
                    id
                    name
                    sku
                    description
                    pickingStrategy
                  }
                  releaseGood {
                    id
                    name
                  }
                  packingType
                  packingSize
                  releaseQty
                  releaseUomValue
                  status
                }
              }
            }
          }
        `,
        variables: { name: this._worksheetNo }
      })

      if (!response.errors) {
        const worksheet = response.data.worksheet
        this._worksheetId = worksheet.id
        this._taskNo = worksheet.taskNo
        this.worksheetDetails = worksheet.worksheetDetails
        this._worksheetStatus = worksheet.status
        this._worksheetType = worksheet.type
        this.assignee = worksheet.assignee || {}

        if (worksheet.orderInventories.length > 0) {
          const { tempOrderInvs, completedOrderInvs, uniqueReleaseGoods } = worksheet.orderInventories.reduce(
            (result, ordInv) => {
              if (!result.uniqueReleaseGoods.find(name => name == ordInv.releaseGood.name))
                result.uniqueReleaseGoods.push(ordInv.releaseGood.name)

              if (
                ordInv.status === ORDER_INVENTORY_STATUS.PENDING_SPLIT.value ||
                ordInv.status === ORDER_INVENTORY_STATUS.COMPLETE_SPLIT.value
              ) {
                ordInv.productSku = ordInv.product.sku
                result.tempOrderInvs.push(ordInv)
              } else {
                ordInv.productSku = ordInv.product.sku
                ordInv.releaseUomValueWithUom = ordInv.releaseUomValue.toFixed(3) + ' ' + ordInv.inventory.uom
                let existingCompOrderInvsIndex = result.completedOrderInvs.findIndex(
                  oinv => oinv.inventory.palletId == ordInv.inventory.palletId
                )

                if (existingCompOrderInvsIndex < 0) {
                  result.completedOrderInvs.push({
                    ...ordInv,
                    releaseGood: [ordInv.releaseGood],
                    qty: ordInv.inventory.qty
                  })
                } else {
                  let existingCompOrderInvs = result.completedOrderInvs[existingCompOrderInvsIndex]
                  result.completedOrderInvs[existingCompOrderInvsIndex] = {
                    ...existingCompOrderInvs,
                    releaseGood: [...existingCompOrderInvs.releaseGood, ordInv.releaseGood],
                    releaseQty: parseFloat((existingCompOrderInvs.releaseQty + ordInv.releaseQty).toFixed(3)),
                    releaseUomValue: existingCompOrderInvs.releaseUomValue + ordInv.releaseUomValue,
                    releaseUomValueWithUom: `${(existingCompOrderInvs.releaseUomValue + ordInv.releaseUomValue).toFixed(
                      3
                    )} ${ordInv.inventory.uom}`
                  }
                }
              }

              return result
            },
            {
              tempOrderInvs: [],
              completedOrderInvs: [],
              uniqueReleaseGoods: []
            }
          )

          this.releaseGoodNoRows = uniqueReleaseGoods.length
          worksheet.releaseGoodNo = uniqueReleaseGoods.join(',\n')

          this.isRecall = uniqueReleaseGoods.map(itm => itm.recall == true)

          // if (this._worksheetStatus !== WORKSHEET_STATUS.DEACTIVATED.value) this.fetchWorksheetDetails()

          this.isPalletPickingOrder = Boolean(!tempOrderInvs || !tempOrderInvs.length)

          let groupedOI = tempOrderInvs.reduce((ordInv, compOrdInv) => {
            var foundOrdInv = ordInv.find(
              ordInv =>
                ordInv.batchId === compOrdInv.batchId &&
                ordInv.product.id === compOrdInv.product.id &&
                ordInv.packingType === compOrdInv.packingType
            )

            if (!foundOrdInv) {
              foundOrdInv = {
                ...compOrdInv,
                extraJsonData: [compOrdInv]
              }
              ordInv.push(foundOrdInv)
              return ordInv
            } else {
              return ordInv.map(oi => {
                if (
                  oi.batchId === compOrdInv.batchId &&
                  oi.product.id === compOrdInv.product.id &&
                  oi.packingType === compOrdInv.packingType
                ) {
                  return {
                    ...oi,
                    releaseQty: oi.releaseQty + compOrdInv.releaseQty,
                    releaseUomValue: oi.releaseUomValue + compOrdInv.releaseUomValue,
                    extraJsonData: [...oi.extraJsonData, compOrdInv]
                  }
                } else {
                  return oi
                }
              })
            }
          }, [])

          this.productGristData = {
            records: orderBy(
              groupedOI.map(ordInv => {
                const { compQty, compUomValue, unassignedQty, unassignedUomValue } = completedOrderInvs.reduce(
                  (result, compOrdInv) => {
                    if (this._checkSameOrderInv(ordInv, compOrdInv)) {
                      result.unassignedQty = compOrdInv.releaseQty - ordInv.releaseQty
                      result.unassignedUomValue = compOrdInv.releaseUomValue - ordInv.releaseUomValue
                      result.compQty = compOrdInv.releaseQty - result.unassignedQty
                      result.compUomValue = compOrdInv.releaseUomValue - result.unassignedUomValue
                    }

                    // need to round off the completed uomValue to bypass the validation
                    result.compUomValue = Math.round(result.compUomValue * 100) / 100

                    return result
                  },
                  { compQty: 0, compUomValue: 0, unassignedQty: 0, unassignedUomValue: 0 }
                )

                return {
                  ...ordInv,
                  ...ordInv.product,
                  completed: compQty === ordInv.releaseQty && compUomValue === ordInv.releaseUomValue
                }
              }),
              ['completed', 'sku'],
              ['asc', 'asc']
            )
          }

          if (completedOrderInvs && completedOrderInvs.length) {
            this.worksheetDetailData = {
              records: completedOrderInvs.map(item =>
                Object.assign(
                  { description: item.description },
                  { sku: item.product.sku },
                  item,
                  item?.inventory,
                  {
                    availableQty: parseFloat(
                      (item.inventory.qty - item.inventory.lockedQty + item.releaseQty).toFixed(3)
                    )
                  },
                  item?.inventory?.location
                )
              )
            }
          }
        } else {
          this.productGristData = {
            records: orderBy(
              worksheet.worksheetDetails.map(wsd => wsd.targetProduct),
              ['completed', 'sku'],
              ['asc', 'asc']
            )
          }
          const { uniqueReleaseGoods } = worksheet.worksheetDetails.reduce(
            (result, wsd) => {
              if (!result?.uniqueReleaseGoods.find(name => name == wsd.targetProduct.releaseGood.name))
                result?.uniqueReleaseGoods.push(wsd.targetProduct.releaseGood.name)

              return result
            },
            {
              uniqueReleaseGoods: []
            }
          )
          this.releaseGoodNoRows = uniqueReleaseGoods.length
          worksheet.releaseGoodNo = uniqueReleaseGoods.join(',\n')

          this.isRecall = uniqueReleaseGoods.map(itm => itm.recall == true)
          this.isPalletPickingOrder = false
        }

        this._fillupForm({
          ...worksheet,
          bizplace: worksheet.bizplace.name,
          assignee: worksheet.assignee?.name || ''
        })
        this.updateContext()
      }
    } catch (e) {
      this._showToast(e)
    } finally {
      this._loading = false
    }
  }

  _checkSameOrderInv(a, b) {
    return (
      a.batchId === b.batchId &&
      a.product?.name === b.product?.name &&
      a.packingType === b.packingType &&
      a.product?.sku === b.product?.sku
    )
  }

  async fetchWorksheetDetails(worksheetNo, batchId, productName, productSku, packingType, packingSize) {
    if (worksheetNo && batchId && productName && productSku && packingType) {
      await this.fetchWorksheetDetailsByProductGroup(
        worksheetNo,
        batchId,
        productName,
        productSku,
        packingType,
        packingSize
      )
    } else {
      await this.fetchWholeWorksheetDetails()
    }
  }

  async fetchWorksheetDetailsByProductGroup(worksheetNo, batchId, productName, productSku, packingType, packingSize) {
    const response = await client.query({
      query: gql`
        query worksheetDetailsByProductGroup(
          $worksheetNo: String!
          $batchId: String!
          $productName: String!
          $productSku: String!
          $packingType: String!
          $packingSize: Float!
        ) {
          worksheetDetailsByProductGroup(
            worksheetNo: $worksheetNo
            batchId: $batchId
            productName: $productName
            productSku: $productSku
            packingType: $packingType
            packingSize: $packingSize
          ) {
            items {
              id
              name
              description
              targetInventory {
                releaseQty
                releaseUomValue
                inventory {
                  qty
                  lockedQty
                  uomValue
                  lockedUomValue
                  batchId
                  palletId
                  cartonId
                  packingType
                  packingSize
                  uom
                  obsolete
                  product {
                    name
                    sku
                    description
                  }
                  location {
                    name
                    description
                    zone
                  }
                }
              }
              status
            }
            total
          }
        }
      `,
      variables: { worksheetNo, batchId, productName, productSku, packingType, packingSize }
    })

    if (!response.errors) {
      const { completedOrderInvs } = response.data.worksheetDetailsByProductGroup.items.reduce(
        (result, ordInv) => {
          ordInv.targetInventory.releaseUomValueWithUom =
            ordInv.targetInventory.releaseUomValue.toFixed(3) + ' ' + ordInv.targetInventory.inventory.uom

          let existingCompOrderInvsIndex = result.completedOrderInvs.findIndex(
            oinv => oinv.inventory.palletId == ordInv.targetInventory.inventory.palletId
          )

          if (existingCompOrderInvsIndex < 0) {
            result.completedOrderInvs.push({
              ...ordInv.targetInventory,
              ...ordInv.targetInventory.inventory,
              sku: ordInv.targetInventory.inventory.product.sku,
              availableQty: ordInv.targetInventory.inventory.qty,
              qty: ordInv.targetInventory.inventory.qty
            })
          } else {
            let existingCompOrderInvs = result.completedOrderInvs[existingCompOrderInvsIndex]
            result.completedOrderInvs[existingCompOrderInvsIndex] = {
              ...existingCompOrderInvs,
              releaseQty: parseFloat((existingCompOrderInvs.releaseQty + ordInv.targetInventory.releaseQty).toFixed(3)),
              releaseUomValue: existingCompOrderInvs.releaseUomValue + ordInv.targetInventory.releaseUomValue
            }
          }

          return result
        },
        {
          completedOrderInvs: []
        }
      )

      this.worksheetDetailData = {
        records: completedOrderInvs,
        total: response.data.worksheetDetailsByProductGroup.total
      }
    }
  }

  async fetchWholeWorksheetDetails() {
    if (!this._worksheetNo) return
    const response = await client.query({
      query: gql`
        query worksheet($name: String!) {
          worksheet(name: $name) {
            worksheetDetails {
              name
              status
              description
              targetInventory {
                batchId
                releaseQty
                releaseUomValue
                product {
                  name
                  sku
                  description
                }
                packingType
                packingSize
                inventory {
                  qty
                  lockedQty
                  palletId
                  cartonId
                  batchId
                  packingType
                  obsolete
                  warehouse {
                    name
                    description
                  }
                  location {
                    name
                    description
                  }
                  product {
                    name
                    sku
                    description
                  }
                  zone
                  uom
                  qty
                }
              }
            }
          }
        }
      `,
      variables: { name: this._worksheetNo }
    })

    if (!response.errors) {
      const worksheetDetails = response.data.worksheet.worksheetDetails

      this.worksheetDetailData = {
        records: worksheetDetails.map(wsd => {
          return {
            ...wsd,
            ...wsd.targetInventory,
            ...wsd.targetInventory.inventory,
            ...wsd.targetInventory.product,
            ...wsd.targetInventory.inventory.warehouse,
            ...wsd.targetInventory.inventory.location,
            name: wsd.name,
            releaseQty: parseFloat(wsd.targetInventory.releaseQty.toFixed(3)),
            releaseUomValue: wsd.targetInventory.releaseUomValue,
            releaseUomValueWithUom:
              wsd.targetInventory.releaseUomValue.toFixed(3) + ' ' + wsd.targetInventory.inventory.uom,
            availableQty: parseFloat(
              (
                wsd.targetInventory.inventory.qty -
                wsd.targetInventory.inventory.lockedQty +
                wsd.targetInventory.releaseQty
              ).toFixed(3)
            )
          }
        })
      }
    }
  }

  _updateGristConfig() {
    const statusColumnConfig = {
      type: 'string',
      name: 'status',
      header: i18next.t('field.status'),
      width: 100
    }

    const batchIdRefColumnConfig = {
      type: 'string',
      name: 'batchIdRef',
      header: i18next.t('field.batch_no_ref'),
      width: 120
    }

    if (this.worksheetDetailData.records.some(e => e.batchIdRef)) {
      this.preWsdGristConfig.columns = [...this.preConfig.columns, batchIdRefColumnConfig]
    }

    if (
      !this.preWsdGristConfig.columns.some(e => e.name === 'status') &&
      this._worksheetStatus !== WORKSHEET_STATUS.DEACTIVATED.value
    ) {
      this.preWsdGristConfig.columns = [...this.preWsdGristConfig.columns, statusColumnConfig]
    } else if (
      this.preWsdGristConfig.columns.some(e => e.name === 'status') &&
      this._worksheetStatus === WORKSHEET_STATUS.DEACTIVATED.value
    ) {
      this.preWsdGristConfig.columns.splice(this.preWsdGristConfig.columns.map(e => e.name).indexOf('status'))
    }

    this.wsdGristConfig = { ...this.preWsdGristConfig }
  }

  _fillupForm(data) {
    for (let key in data) {
      Array.from(this.form.querySelectorAll('input, select, textarea')).forEach(field => {
        if (field.name === key && field.type === 'checkbox') {
          field.checked = data[key]
        } else if (field.name === key) {
          if (data[key] instanceof Object) {
            const objectData = data[key]
            field.value = `${objectData.name} ${objectData.description ? `(${objectData.description})` : ''}`
          } else {
            field.value = data[key]
          }
        }
      })
    }
  }

  _clearAll() {
    this.form.reset()
    this.productGristData = { records: [] }
    this.worksheetDetailData = { records: [] }
  }

  _showInventoryAssignPopup() {
    if (!this._loading) {
      try {
        if (!this._selectedProduct) throw new Error(i18next.t('text.there_is_no_selected_product'))
        openPopup(
          html`
            <inventory-assign-popup
              .worksheetId="${this._worksheetId}"
              .worksheetNo="${this._worksheetNo}"
              .batchId="${this._selectedProduct.batchId}"
              .productId="${this._selectedProduct.product.id}"
              .productName="${this._selectedProduct.product.name}"
              .productSku="${this._selectedProduct.product.sku}"
              .productPickingStrategy="${this._selectedProduct.product.pickingStrategy}"
              .bizplaceId="${this._selectedProduct.bizplaceId}"
              .worksheetType="${this._worksheetType}"
              .packingType="${this._selectedProduct.packingType}"
              .packingSize="${this._selectedProduct.packingSize}"
              .uom="${this._selectedProduct.uom}"
              .releaseQty="${this._selectedProduct.releaseQty}"
              .releaseUomValue="${this._selectedProduct.releaseUomValue}"
              .orderProductId="${this._selectedProduct.orderProductId}"
              @completed="${async () => {
                this._spinner(true)

                await this.fetchOrderInventories()

                this._selectedProduct.completed = true

                this._spinner(false)

                this.updateContext()
              }}"
            ></inventory-assign-popup>
          `,
          {
            backdrop: true,
            size: 'large',
            title: i18next.t('title.inventory_assign')
          }
        )
      } catch (e) {
        this._showToast(e)
      }
    }
  }

  _showAutoAssignPopup() {
    if (!this._loading) {
      openPopup(
        html`
          <inventory-auto-assign-popup
            .worksheetId="${this._worksheetId}"
            .worksheetNo="${this._worksheetNo}"
            .worksheetType="${this._worksheetType}"
            .data="${this.productGrist.data}"
            @completed="${async () => {
              this._spinner(true)

              await this.fetchOrderInventories()

              this._spinner(false)

              this.updateContext()
            }}"
          ></inventory-auto-assign-popup>
        `,
        {
          backdrop: true,
          size: 'large',
          title: i18next.t('title.inventory_auto_assign')
        }
      )
    }
  }

  async _openItemLabelPrintPopup() {
    const _items = {
      records: this.worksheetDetails.map(itm => {
        return {
          batchId: itm.targetInventory.batchId,
          sku: itm.targetInventory.product.sku,
          product: itm.targetInventory.product,
          printQty: parseFloat(itm.targetInventory.releaseQty.toFixed(3)),
          releaseQty: parseFloat(itm.targetInventory.releaseQty.toFixed(3)),
          attentionTo: itm.targetInventory.releaseGood.attentionTo?.toUpperCase() || '-',
          attentionCompany: itm.targetInventory.releaseGood.attentionCompany?.toUpperCase() || '-',
          roNo: itm.targetInventory.releaseGood.name,
          refNo: itm.targetInventory.releaseGood.refNo || '-',
          city: itm.targetInventory.releaseGood.city?.toUpperCase() || '-',
          releaseDate: itm.targetInventory.releaseGood.releaseDate || '-'
        }
      })
    }

    openPopup(html` <item-label-popup .items="${_items}"></item-label-popup> `, {
      backdrop: true,
      size: 'large',
      title: i18next.t('title.select_item_label')
    })
  }

  _spinner(show) {
    if (show) {
      this._loading = true
      if (this?.productGrist) {
        this.productGrist.showSpinner()
      }
      if (this?.wsdGrist) {
        this.wsdGrist.showSpinner()
      }
    } else {
      this._loading = false
      if (this?.productGrist) {
        this.productGrist.hideSpinner()
      }
      if (this?.wsdGrist) {
        this.wsdGrist.hideSpinner()
      }
    }
  }

  async _undoAssignment() {
    if (!this._loading) {
      try {
        const result = await CustomAlert({
          title: i18next.t('title.are_you_sure'),
          text: i18next.t('text.undo_picking_worksheet'),
          confirmButton: { text: i18next.t('button.confirm') },
          cancelButton: { text: i18next.t('button.cancel') }
        })

        if (!result.value) {
          this._spinner(false)
          return
        }

        this._spinner(true)
        await client.mutate({
          mutation: gql`
            mutation undoPickingAssigment(
              $worksheetNo: String!
              $batchId: String!
              $productId: String!
              $packingType: String!
              $packingSize: Float!
            ) {
              undoPickingAssigment(
                worksheetNo: $worksheetNo
                batchId: $batchId
                productId: $productId
                packingType: $packingType
                packingSize: $packingSize
              )
            }
          `,
          variables: {
            worksheetNo: this._worksheetNo,
            batchId: this._selectedProduct.batchId,
            productId: this._selectedProduct.product.id,
            packingType: this._selectedProduct.packingType,
            packingSize: this._selectedProduct.packingSize
          }
        })

        await this.fetchOrderInventories()
        // await this.fetchWorksheetDetails(
        //   this._worksheetNo,
        //   this._selectedProduct.batchId,
        //   this._selectedProduct.product.name,
        //   this._selectedProduct.product.sku,
        //   this._selectedProduct.packingType
        // )

        this._selectedProduct.completed = false
        this.updateContext()
      } catch (e) {
        this._showToast(e)
      } finally {
        this._spinner(false)
      }
    }
  }

  async _activateWorksheet() {
    if (!this._loading) {
      try {
        const result = await CustomAlert({
          title: i18next.t('title.are_you_sure'),
          text: i18next.t('text.activate_picking_worksheet'),
          confirmButton: { text: i18next.t('button.confirm') },
          cancelButton: { text: i18next.t('button.cancel') }
        })

        if (!result.value) {
          this._spinner(false)
          return
        }

        this._spinner(true)

        const response = await client.mutate({
          mutation: gql`
            mutation activateBatchPicking($worksheetNo: String!) {
              activateBatchPicking(worksheetNo: $worksheetNo) {
                name
              }
            }
          `,
          variables: { worksheetNo: this._worksheetNo }
        })
        if (!response.errors) {
          this._showToast({ message: i18next.t('text.worksheet_activated') })
          await this.fetchOrderInventories()
          this.updateContext()
          navigate(`merged_outbound_worksheets`)
        }
      } catch (e) {
        this._showToast(e)
      } finally {
        this._spinner(false)
      }
    }
  }

  _getPickingWorksheetDetails() {
    return this.productGrist.dirtyData.records.map(worksheetDetail => {
      return {
        name: worksheetDetail.name,
        description: worksheetDetail.description
      }
    })
  }

  _selectOperator() {
    openPopup(
      html`
        <select-operator-popup
          .bizplace=${this.targetBizpace}
          @updateOperator="${async e => {
            this.assignee = e.detail
            this.operatorInput.value = this.assignee.name || ''
            await this.assignWorker()

            if (this.activatable) {
              if (this.orderNo) {
                history.back()
              }
            }
          }}"
        ></select-operator-popup>
      `,
      {
        backdrop: true,
        size: 'medium',
        title: 'select operator'
      }
    )
  }

  async assignWorker() {
    const response = await client.mutate({
      mutation: gql`
        mutation assignBatchPickingWorker($worksheetId: [String]!, $userId: String!) {
          assignPickingWorker(worksheetId: $worksheetId, userId: $userId)
        }
      `,
      variables: { worksheetId: [this._worksheetId], userId: this.assignee.id }
    })

    if (!response.errors) {
      return this._showToast({ message: i18next.t('text.updated_successfully') })
    }
  }

  _openReassignInventoryPopup() {
    openPopup(
      html`
        <inventory-reassign-popup
          .bizplaceId=${this.targetBizpace?.id}
          .taskNo=${this._taskNo}
          .worksheetNo=${this._worksheetNo}
          @reassignment-completed="${async () => {
            await this.fetchOrderInventories()
            await this.fetchWorksheetDetails(this._worksheetNo)

            this.updateContext()
          }}"
        ></inventory-reassign-popup>
      `,
      {
        escapable: false,
        closable: false,
        backdrop: true,
        size: 'large',
        title: i18next.t('title.reassign_inventory')
      }
    )
  }

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

window.customElements.define('worksheet-batch-picking', WorksheetBatchPicking)
