import '@things-factory/grist-ui'
import '@things-factory/form-ui'

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

import { sleep } from '@operato/utils'
import { i18next, localize } from '@things-factory/i18n-base'
import { client } from '@things-factory/shell'
import { isMobileDevice } from '@things-factory/utils'

import { fetchLocationSortingRule } from '../../fetch-location-sorting-rule'
import { fetchSettingRule } from '../../fetch-setting-value'
import { INVENTORY_STATUS, LOCATION_SORTING_RULE, ORDER_TYPES } from '../constants'

class InventoryReassignPopup extends localize(i18next)(LitElement) {
  static get properties() {
    return {
      _orderProductSearchFields: Array,
      orderProductConfig: Object,
      orderInventoryConfig: Object,
      orderProductData: Array,
      orderInventoryData: Array,
      _selectedOrderProduct: Object,
      roId: String,
      taskNo: String,
      worksheetNo: String,
      bizplaceId: String,
      recallOption: Boolean,
      _itemNotReassignable: Boolean,
      _strictProductSelection: Boolean,
      worksheetPickingAssignment: Boolean
    }
  }

  static get styles() {
    return [
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow: hidden;
          background-color: white;
        }
        .grist {
          flex: 1;
          display: flex;
          flex-direction: column;
          overflow: auto;
        }
        .grist-container {
          overflow-y: hidden;
          display: flex;
          flex: 1;
          padding: 5px;
        }
        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);
        }
        .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);
        }
      `
    ]
  }

  render() {
    return html`<div class="grist-container">
        <div class="grist">
          <h2>
            <mwc-icon>list_alt</mwc-icon>${i18next.t('title.product')}
            (${this._selectedOrderProduct?.product?.sku || ''})
          </h2>
          <search-form
            id="orderProductSearchForm"
            .fields=${this._orderProductSearchFields}
            @submit=${e => this.orderProductGrist.fetch()}
          ></search-form>
          <data-grist
            id="orderProduct"
            .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
            .config=${this.orderProductConfig}
            .fetchHandler="${this.fetchOrderProducts.bind(this)}"
          ></data-grist>
        </div>
      </div>

      ${this._selectedOrderProduct
        ? html`<div class="grist-container">
            <div class="grist">
              <h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.inventory')}</h2>
              <data-grist
                id="orderInventory"
                .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
                .config=${this.orderInventoryConfig}
                .data=${this.orderInventoryData}
                @record-change="${this._onProductChangeHandler.bind(this)}"
                @field-change="${this._onInventoryFieldChanged.bind(this)}"
              ></data-grist>
            </div>
          </div>`
        : ''}

      <div class="button-container">
        ${this._selectedOrderProduct
          ? html`<mwc-button
              label="${`${i18next.t('button.update')}`}"
              @click=${async e => {
                const button = e.currentTarget
                this.disableButton(button)

                try {
                  await this.reassignInventories()
                } finally {
                  await sleep(200)
                  this.enableButton(button)
                }
              }}
              raised
            ></mwc-button>`
          : ''}
        <mwc-button
          label="${`${i18next.t('button.close')}`}"
          @click="${() => {
            this.dispatchEvent(new CustomEvent('reassignment-completed'))
            history.back()
          }}"
          raised
        ></mwc-button>
      </div> `
  }

  disableButton(button) {
    button.icon = 'rotate_right'
    button.setAttribute('working', true)
    button.disabled = true
  }

  enableButton(button) {
    button.disabled = false
    button.icon = ''
    button.removeAttribute('working')
  }

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

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

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

  async firstUpdated() {
    const locationSortingRules = await fetchLocationSortingRule(LOCATION_SORTING_RULE.INVENTORY_ASSIGNMENT.value)

    this._orderProductSearchFields = [
      {
        name: 'productInfo',
        label: i18next.t('field.product_info'),
        type: 'text',
        props: { searchOper: 'eq' }
      }
    ]

    this.orderProductConfig = {
      pagination: { pages: [10, 20, 50, 100] },
      rows: {
        appendable: false,
        handlers: {
          click: async (columns, data, column, record, rowIndex) => {
            if (record != undefined) {
              this._selectedOrderProduct = record
              this.bizplace = record.bizplace.id
              this.recallOption = record?.releaseGood?.recall || false
              this._updateOrderInventoryConfig()
              await this.fetchOrderInventories({ page: 1, limit: 9999999 })
            }
          }
        }
      },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'string',
          name: 'releaseOrderNo',
          header: i18next.t('field.release_order_no'),
          width: 200
        },
        {
          type: 'string',
          name: 'batchId',
          header: i18next.t('field.batch_no'),
          width: 100
        },
        {
          type: 'string',
          name: 'productSKU',
          header: i18next.t('field.sku'),
          width: 100
        },
        {
          type: 'object',
          name: 'product',
          header: i18next.t('field.product'),
          width: 150
        },
        {
          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: 'string',
          name: 'uom',
          header: i18next.t('field.uom'),
          width: 100
        },
        {
          type: 'float',
          name: 'releaseQty',
          header: i18next.t('field.release_qty'),
          width: 140
        },
        {
          type: 'float',
          name: 'releaseUomValue',
          header: i18next.t('field.release_uom_value'),
          width: 140
        },
        {
          type: 'boolean',
          name: 'obsolete',
          header: i18next.t('field.obsolete'),
          width: 60
        }
      ]
    }

    this.orderInventoryConfig = {
      pagination: { infinite: true },
      rows: {
        appendable: true,
        handlers: {
          click: (columns, data, column, record, rowIndex) => {
            if (record != undefined && record?.notReassignable) {
              this._itemNotReassignable = true
            } else {
              this._itemNotReassignable = false
            }
            this._updateOrderInventoryConfig()
          }
        }
      },
      list: { fields: ['inventory', 'product', 'location', 'releaseQty'] },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'gutter',
          gutterName: 'button',
          icon: 'close',
          handlers: {
            click: (columns, data, column, record, rowIndex) => {
              if (record != undefined && !record.notReassignable) {
                const newData = data.records.filter((_, idx) => idx !== rowIndex)
                this.orderInventoryData = { ...this.orderInventoryData, records: newData }
                this.orderInventoryGrist.dirtyData.records = newData
                this._updateOrderInventoryConfig()
              } else {
                this._showToast({ message: i18next.t('text.picked_inventory_not_allowed_to_reassign') })
              }
            }
          }
        },
        {
          type: 'object',
          name: 'inventory',
          header: i18next.t('field.inventory_list'),
          record: {
            editable: true,
            options: {
              queryName: 'inventoriesByPallet',
              basicArgs: {
                filters: [{ name: 'status', operator: 'eq', value: INVENTORY_STATUS.STORED.value }],
                locationSortingRules
              },
              nameField: 'batchId',
              descriptionField: 'palletId',
              select: [
                { name: 'id', hidden: true },
                { name: 'name', hidden: true },
                { name: 'remainUomValue', hidden: true },
                { name: 'product', type: 'object', hidden: true },
                { name: 'palletId', header: i18next.t('field.lot_id') },
                { name: 'cartonId', header: i18next.t('field.carton_id') },
                { name: 'productSKU', header: i18next.t('field.sku') },
                { name: 'productName', header: i18next.t('field.product_info') },
                { name: 'productBrand', header: i18next.t('field.brand') },
                { name: 'batchId', header: i18next.t('field.batch_id') },
                {
                  name: 'location',
                  type: 'object',
                  queryName: 'locations',
                  field: 'name'
                },
                { name: 'packingType', header: i18next.t('field.packing_type') },
                { name: 'packingSize', header: i18next.t('field.packing_size') },
                { name: 'uom', header: i18next.t('field.uom') },
                { name: 'remainQty', type: 'float', header: i18next.t('field.remain_qty') },
                {
                  name: 'remainUomValueWithUom',
                  type: 'string',
                  header: i18next.t('field.total_uom_value')
                },
                { name: 'batchIdRef', header: i18next.t('field.batch_no_ref') },
                { name: 'expirationDate', type: 'date', header: i18next.t('field.expiry_date') },
                { name: 'manufactureDate', type: 'date', header: i18next.t('field.manufacture_date') },
                {
                  name: 'remark',
                  type: 'string',
                  header: i18next.t('field.remark')
                }
              ],
              list: {
                fields: ['palletId', 'cartonId', 'batchId', 'location', 'batchIdRef']
              }
            }
          },
          width: 250
        },
        {
          type: 'object',
          name: 'product',
          header: i18next.t('field.product'),
          width: 150
        },
        {
          type: 'string',
          name: 'productBrand',
          header: i18next.t('field.brand'),
          width: 100
        },
        {
          type: 'object',
          name: 'location',
          header: i18next.t('field.location'),
          width: 150
        },
        {
          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: 'string',
          name: 'uom',
          header: i18next.t('field.uom'),
          width: 100
        },
        {
          type: 'float',
          name: 'addableQty',
          header: i18next.t('field.remaining_qty'),
          width: 100
        },
        {
          type: 'float',
          name: 'releaseQty',
          header: i18next.t('field.release_qty'),
          record: { editable: true, options: { min: 0 } },
          width: 100
        },
        {
          type: 'string',
          name: 'addableUomValue',
          header: i18next.t('field.remaining_uom_value'),
          width: 100
        },
        {
          type: 'float',
          name: 'releaseUomValue',
          header: i18next.t('field.release_uom_value'),
          record: { editable: true, options: { min: 0 } },
          width: 140
        },
        {
          type: 'string',
          name: 'batchIdRef',
          header: i18next.t('field.batch_no_ref'),
          width: 100
        },
        {
          type: 'date',
          name: 'expirationDate',
          header: i18next.t('field.expiry_date'),
          width: 150
        },
        {
          type: 'date',
          name: 'manufactureDate',
          header: i18next.t('field.manufacture_date'),
          width: 150
        }
      ]
    }
  }

  async _fetchReleaseOrderList(taskNo) {
    try {
      const response = await client.query({
        query: gql`
          query findReleaseOrdersByTaskNo($taskNo: String!) {
            findReleaseOrdersByTaskNo(taskNo: $taskNo) {
              releaseGoods {
                id
                name
                status
              }
              taskNo
            }
          }
        `,
        variables: { taskNo }
      })

      if (!response.errors) {
        let releaseOrders = response.data.findReleaseOrdersByTaskNo.releaseGoods

        if (releaseOrders?.length) {
          return releaseOrders
        } else {
          return []
        }
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  async fetchOrderProducts({ page, limit, sorters = [{ name: 'createdAt', desc: true }] }) {
    let filters = this.orderProductSearchForm.queryFilters

    if (this.roId) {
      filters.push({
        name: 'releaseGood',
        operator: 'in',
        value: [this.roId]
      })
    }

    if (this.taskNo) {
      const releaseGoods = await this._fetchReleaseOrderList(this.taskNo)
      filters.push({
        name: 'releaseGood',
        operator: 'in',
        value: releaseGoods.map(rg => rg.id)
      })
    }

    const response = await client.query({
      query: gql`
        query orderProducts($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
          orderProducts(filters: $filters, pagination: $pagination, sortings: $sortings) {
            items {
              id
              name
              batchId
              batchIdRef
              packingType
              packingSize
              uom
              releaseQty
              releaseUomValue
              status
              bizplace {
                id
                name
                domain {
                  id
                }
              }
              product {
                id
                name
                description
                sku
              }
              productDetail {
                id
              }
              releaseGood {
                id
                name
                recall
              }
            }
            total
          }
        }
      `,
      variables: {
        filters,
        pagination: { page, limit },
        sortings: sorters
      }
    })

    if (!response.errors) {
      this.orderProductData =
        response.data.orderProducts.items.map(item => {
          return {
            ...item,
            productSKU: item.product.sku,
            releaseOrderNo: item.releaseGood.name
          }
        }) || []

      if (this.orderProductData?.length > 0) {
        this._selectedOrderProduct = this.orderProductData[0]
        this.recallOption = this.orderProductData[0]?.releaseGood?.recall || false
        if (!this.bizplaceId) this.bizplaceId = this._selectedOrderProduct?.bizplace?.id

        this._strictProductSelection = await fetchSettingRule(
          'strict-product-selection',
          this._selectedOrderProduct?.bizplace?.domain?.id
        )
        await this.fetchOrderInventories({ page: 1, limit: 9999999 })
      } else {
        this._selectedOrderProduct = null
      }
    }
  }

  async fetchOrderInventories({ page, limit, sorters = [{ name: 'inventoryPalletId' }] }) {
    let filters = [
      {
        name: 'orderProductId',
        operator: 'eq',
        value: this._selectedOrderProduct.id
      }
    ]

    const response = await client.query({
      query: gql`
        query orderInventories($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
          orderInventories(filters: $filters, pagination: $pagination, sortings: $sortings) {
            items {
              id
              name
              batchId
              packingType
              packingSize
              uom
              releaseQty
              releaseUomValue
              pickedQty
              status
              inventory {
                id
                palletId
                cartonId
                batchId
                batchIdRef
                qty
                lockedQty
                uom
                uomValue
                lockedUomValue
                obsolete
                manufactureDate
                expirationDate
                product {
                  id
                  name
                  description
                  sku
                  brand
                }
                warehouse {
                  name
                  description
                }
                location {
                  name
                  description
                }
              }
            }
            total
          }
        }
      `,
      variables: {
        filters,
        pagination: { page, limit },
        sortings: sorters
      }
    })

    if (!response.errors) {
      let isObsolete
      const data = response.data.orderInventories.items.map(item => {
        if (item?.inventory?.obsolete) {
          isObsolete = true
        }
        return {
          ...item,
          product: item.inventory.product,
          productBrand: item.inventory.product.brand,
          location: item.inventory.location,
          addableQty: Math.round(item.inventory.qty - item.inventory.lockedQty),
          addableUomValue: Math.round(item.inventory.uomValue - item.inventory.lockedUomValue),
          remainQty: Math.round(item.inventory.qty - item.inventory.lockedQty),
          remainUomValue: Math.round(item.inventory.uomValue - item.inventory.lockedUomValue),
          remainUomValueWithUom: `${item.inventory.uomValue - item.inventory.lockedUomValue} ${item.inventory.uom}`,
          notReassignable: item?.pickedQty && !isObsolete ? true : false,
          manufactureDate: item?.inventory.manufactureDate,
          expirationDate: item?.inventory.expirationDate
        }
      })
      this.orderInventoryData = {
        records: data
      }

      this.orderProductGrist.data = {
        total: this.orderProductData?.length || 0,
        records: this.orderProductData
      }

      this.orderProductData = this.orderProductData.map(itm => {
        if (itm.id === this._selectedOrderProduct?.id) {
          itm.obsolete = isObsolete
        }

        return itm
      })

      this._updateOrderInventoryConfig()
    }
  }

  _onProductChangeHandler(event) {
    const changeRecord = event.detail.after
    const beforeRecord = event.detail.before
    const changedColumn = event.detail.column.name
    let totalAvailableQty = 0
    let totalAvailableUomValue = 0

    try {
      if (Number.isNaN(changeRecord.releaseQty) || Number.isNaN(changeRecord.releaseUomValue)) {
        throw new Error(i18next.t('text.invalid_form_value'))
      }

      if (event.detail.after.__dirty__ == '+') {
        totalAvailableQty = changeRecord.remainQty
        totalAvailableUomValue = changeRecord.remainUomValue
      } else {
        totalAvailableQty = beforeRecord.addableQty + beforeRecord.releaseQty
        totalAvailableUomValue = beforeRecord.addableUomValue + beforeRecord.releaseUomValue
      }

      if (changedColumn === 'releaseQty') {
        this._validateReleaseQty(changeRecord, totalAvailableQty)
      } else if (changedColumn === 'releaseUomValue') {
        this._validateReleaseUomValue(changeRecord, totalAvailableUomValue)
      }
      this._updateOrderInventoryConfig()
    } catch (e) {
      const columnName = event.detail.column.name
      const beforeValue = event.detail.before && event.detail.before[columnName]
      const afterValue = event.detail.after && event.detail.after[columnName]
      if (beforeValue) {
        if (columnName == 'releaseQty') {
          event.detail.after['addableQty'] = event.detail.before['addableQty']
        }
        event.detail.after[columnName] = beforeValue
      } else {
        if (columnName == 'releaseQty') {
          event.detail.after['addableQty'] = afterValue
        }
        event.detail.after[columnName] = null
      }
      this._showToast(e)
    }
  }

  _validateReleaseQty(changeRecord, totalAvailableQty) {
    if (changeRecord.remainQty === undefined) throw new Error(i18next.t('text.there_is_no_selected_items'))
    if (totalAvailableQty) {
      if (changeRecord.releaseQty < 0) {
        throw new Error(i18next.t('text.invalid_quantity_input'))
      } else if (changeRecord.releaseQty > totalAvailableQty) {
        throw new Error(i18next.t('text.available_quantity_insufficient'))
      }
    } else {
      if (changeRecord.releaseQty > changeRecord.remainQty) {
        throw new Error(i18next.t('text.available_quantity_insufficient'))
      }
    }

    if (changeRecord?.notReassignable) {
      if (changeRecord.releaseQty < changeRecord.pickedQty) {
        throw new Error(i18next.t('text.release_qty_cannot_exceed_picked_qty'))
      }
    }
  }

  _validateReleaseUomValue(changeRecord, totalAvailableUomValue) {
    if (changeRecord.remainUomValue === undefined) throw new Error(i18next.t('text.there_is_no_selected_items'))
    if (totalAvailableUomValue) {
      if (changeRecord.releaseUomValue < 0) {
        throw new Error(i18next.t('text.invalid_quantity_input'))
      } else if (changeRecord.releaseUomValue > totalAvailableUomValue) {
        throw new Error(i18next.t('text.available_uom_value_insufficient'))
      }
    } else {
      if (changeRecord.releaseUomValue > remainUomValue) {
        throw new Error(i18next.t('text.available_uom_value_insufficient'))
      }
    }
  }

  _onInventoryFieldChanged(e) {
    let columnName = e.detail.column.name
    let roundedUomValue = e.detail.record.roundedUomValue || 0
    let releaseQty = 0
    let packageUomValue = 0

    try {
      if (e.details?.after && e.details?.after !== 0) {
        throw new Error(i18next.t('text.invalid_form_value'))
      }

      const result = this._calculateQtyAndUom(
        packageUomValue,
        columnName,
        e.detail.record.uomValue,
        e.detail.record.qty,
        e.detail.record?.__origin__?.releaseUomValue || 0,
        e.detail.record?.__origin__?.releaseQty || 0,
        e.detail.record?.__origin__?.addableUomValue || e.detail.after.remainUomValue,
        e.detail.record?.__origin__?.addableQty || e.detail.after.remainQty,
        e.detail.record?.__origin__?.remainUomValue || e.detail.after.remainUomValue,
        e.detail.record?.__origin__?.remainQty || e.detail.after.remainQty,
        e.detail.after
      )

      if (columnName == 'releaseUomValue' || columnName == 'releaseQty' || columnName == 'inventory') {
        if (columnName == 'inventory') {
          if (
            e.detail.after.remainUomValue &&
            e.detail.after.remainQty &&
            e.detail.after.remainUomValue > 0 &&
            e.detail.after.remainQty > 0
          ) {
            releaseQty = e.detail.record.releaseQty || 0

            roundedUomValue = releaseQty * (e.detail.after.remainUomValue / e.detail.after.remainQty)

            roundedUomValue = parseFloat(roundedUomValue.toFixed(3))
          }
        } else {
          let packageUomValue = e.detail.record.remainUomValue / e.detail.record.remainQty
          if (
            e.detail.record.remainUomValue &&
            e.detail.record.remainQty &&
            e.detail.record.remainUomValue > 0 &&
            e.detail.record.remainQty > 0
          ) {
            if (columnName === 'releaseQty') {
              releaseQty = e.detail.after || 0
            } else {
              releaseQty = Math.round(e.detail.after / packageUomValue)
            }

            roundedUomValue = releaseQty * packageUomValue
            roundedUomValue = parseFloat(roundedUomValue.toFixed(3))
            this.releaseQty = releaseQty
            this.releaseUomValue = roundedUomValue
          }
        }
      }

      this.orderInventoryData = {
        ...this.orderInventoryData,
        ...this.orderInventoryGrist.dirtyData,
        records: this.orderInventoryGrist.dirtyData.records.map((record, idx) => {
          if (columnName == 'inventory' && idx === e.detail.row) {
            if (this.releaseQty > e.detail.record.remainQty && this.releaseUomValue > e.detail.record.remainUomValue) {
              record.releaseQty = e.detail.record.releaseQty
              record.releaseUomValue = e.detail.record.releaseUomValue
            } else {
              record.releaseQty = releaseQty
              record.releaseUomValue = roundedUomValue
            }
            record.remainQty = e.detail.after.remainQty
            record.remainUomValue = e.detail.after.remainUomValue
            record.addableQty = e.detail.after.remainQty
            record.addableUomValue = e.detail.after.remainUomValue
            if (record?.__origin__) {
              record.__origin__.addableQty = e.detail.after.remainQty
              record.__origin__.addableUomValue = e.detail.after.remainUomValue
            }
            if (record.releaseQty > 0 && record.releaseUomValue > 0) {
              record.addableQty = record.addableQty - record.releaseQty
              if (record.addableQty <= 0) {
                record.addableQty = 0
              }
              if (record.addableUomValue == 0) {
                record.addableUomValue = record.addableQty * (record.releaseUomValue / record.releaseQty)
              } else {
                if (record.addableQty == 0) {
                  record.addableUomValue = 0
                } else {
                  if (e.detail.record.releaseQty == 0 || e.detail.record.releaseUomValue == 0) {
                    record.addableUomValue =
                      record.addableQty * (e.detail.record.addableUomValue / e.detail.record.addableQty)
                  } else {
                    record.addableUomValue =
                      record.addableQty * (e.detail.record.releaseUomValue / e.detail.record.releaseQty)
                  }
                }
              }
            }
          }

          if (result.releaseQty >= 0 && result.roundedUom >= 0) {
            if ((columnName == 'releaseUomValue' || columnName == 'releaseQty') && idx === e.detail.row) {
              if (columnName == 'releaseUomValue') {
                record.releaseQty = result.releaseQty
              }
              record.releaseUomValue = result.roundedUom
              if (record.__dirty__ == '+') {
                if (result.releaseQty == record.__origin__.addableQty) {
                  record.addableQty = record.__origin__.addableQty - result.releaseQty
                } else {
                  record.addableQty = record.__origin__.releaseQty + record.__origin__.addableQty - result.releaseQty
                }

                if (record.releaseQty == 0) {
                  record.releaseUomValue = 0
                  record.addableQty = record.remainQty
                }
              } else {
                if (record.releaseQty == record.__origin__.releaseQty) {
                  record.addableQty = record.__origin__.releaseQty + record.__origin__.addableQty - record.releaseQty
                } else {
                  record.addableQty = record.__origin__.releaseQty + record.__origin__.addableQty - result.releaseQty
                }
              }

              if (record.addableQty <= 0) {
                record.addableQty = 0
              }
              if (record.addableUomValue == 0) {
                record.addableUomValue =
                  record.addableQty * (record.__origin__.releaseUomValue / record.__origin__.releaseQty)
              } else {
                if (record.addableQty == 0) {
                  record.addableUomValue = 0
                } else {
                  if (e.detail.record.__origin__.releaseQty == 0 || e.detail.record.__origin__.releaseUomValue == 0) {
                    record.addableUomValue =
                      record.addableQty *
                      (e.detail.record.__origin__.addableUomValue / e.detail.record.__origin__.addableQty)
                  } else {
                    record.addableUomValue =
                      record.addableQty *
                      (e.detail.record.__origin__.releaseUomValue / e.detail.record.__origin__.releaseQty)
                  }
                }
              }
            }
          }

          let returnObj = {
            ...record,
            ...record.inventory,
            name: record.name ? record.name : idx
          }

          return returnObj
        })
      }

      this._updateOrderInventoryConfig()
    } catch (e) {
      this._showToast(e)
    }
  }

  _calculateQtyAndUom(
    packageUom,
    columnName,
    detailUom,
    detailQty,
    originUom = 0,
    originQty = 0,
    originAddableUom,
    originAddableQty,
    originRemainUom,
    originRemainQty,
    afterValue
  ) {
    var releaseQty = 0
    var roundedUom = 0

    if (afterValue >= 0) {
      if (columnName == 'releaseUomValue' || columnName == 'releaseQty') {
        if (originQty >= 0) {
          if (originQty == 0 || originUom == 0) {
            packageUom = originAddableUom / originAddableQty
          } else {
            packageUom = originUom / originQty
          }
        } else {
          packageUom = originRemainUom / originRemainQty
        }

        if (columnName === 'releaseQty') {
          if (afterValue - originQty <= originAddableQty) {
            releaseQty = afterValue || 0
          } else {
            releaseQty = originQty
          }
        } else if (columnName === 'releaseUomValue') {
          if (afterValue - originUom <= originAddableUom) {
            releaseQty = Math.round(afterValue / packageUom)
          } else {
            releaseQty = Math.round(originUom / packageUom)
          }
        }

        roundedUom = releaseQty * packageUom
        roundedUom = parseFloat(roundedUom.toFixed(3))
      }
    } else {
      releaseQty = afterValue
      roundedUom = afterValue
    }

    return { releaseQty, roundedUom }
  }

  _updateOrderInventoryConfig() {
    const _selectedInventories = (this.orderInventoryGrist.dirtyData.records || this.orderInventoryData.records).map(
      record => record.inventory.id
    )
    this.orderInventoryConfig = {
      ...this.orderInventoryConfig,
      columns: this.orderInventoryConfig.columns.map(column => {
        if (column.name === 'inventory') {
          column.record.editable = !this._itemNotReassignable
          column.record.options.basicArgs = {
            ...column.record.options.basicArgs,
            filters: [...column.record.options.basicArgs.filters.filter(filter => filter.name !== 'id')]
          }

          if (this._selectedOrderProduct) {
            column.record.options.basicArgs.filters = [
              { name: 'status', operator: 'eq', value: INVENTORY_STATUS.STORED.value },
              { name: 'productName', operator: 'eq', value: this._selectedOrderProduct.product.sku },
              { name: 'recall', operator: '', value: this.recallOption },
              { name: 'skipLockCheck', operator: '', value: true }
            ]
          }

          if (this._strictProductSelection) {
            column.record.options.basicArgs.filters = [
              ...column.record.options.basicArgs.filters,
              { name: 'productDetailId', operator: 'eq', value: this._selectedOrderProduct.productDetail.id }
            ]
          } else {
            column.record.options.basicArgs.filters = [
              ...column.record.options.basicArgs.filters,
              {
                name: 'packingType',
                value: this.orderInventoryData.records[0].packingType,
                operator: 'eq'
              },
              {
                name: 'packingSize',
                value: this.orderInventoryData.records[0].packingSize,
                operator: 'eq'
              },
              {
                name: 'uom',
                value: this.orderInventoryData.records[0].uom,
                operator: 'eq'
              }
            ]
          }

          if (_selectedInventories.length) {
            column.record.options.basicArgs.filters = [
              ...column.record.options.basicArgs.filters,
              {
                name: 'id',
                value: _selectedInventories,
                operator: 'notin'
              }
            ]
          }

          if (this.bizplaceId) {
            column.record.options.basicArgs.filters = [
              ...column.record.options.basicArgs.filters,
              {
                name: 'bizplace_id',
                operator: 'eq',
                value: this.bizplaceId
              }
            ]
          }
        }

        return column
      })
    }

    this.orderInventoryData = {
      ...this.orderInventoryData
    }
  }

  _validateInventories() {
    let inventoryData = this.orderInventoryData.records
    let orderProduct = this._selectedOrderProduct

    if (inventoryData.some(({ releaseQty }) => releaseQty <= 0)) {
      throw new Error(i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.release_qty') } }))
    }

    if (inventoryData.some(({ releaseUomValue }) => releaseUomValue <= 0)) {
      throw new Error(i18next.t('text.x_should_be_positive', { state: { x: i18next.t('label.release_uom_value') } }))
    }

    let totalReleaseQty = inventoryData.reduce((qty, record) => {
      if (record.releaseQty > 0) {
        qty += record.releaseQty
      }
      return qty
    }, 0)

    if (totalReleaseQty != orderProduct.releaseQty) throw new Error(i18next.t('text.release_qty_not_matched'))
  }

  async reassignInventories() {
    try {
      this._validateInventories()

      let response = await client.mutate({
        mutation: gql`
          mutation regenerateReleaseGoodWorksheetDetails(
            $worksheetNo: String!
            $batchId: String!
            $productId: String!
            $productDetailId: String!
            $packingType: String!
            $packingSize: Float!
            $orderProductId: String!
            $worksheetDetails: [NewWorksheetDetail]
          ) {
            regenerateReleaseGoodWorksheetDetails(
              worksheetNo: $worksheetNo
              batchId: $batchId
              productId: $productId
              productDetailId: $productDetailId
              packingType: $packingType
              packingSize: $packingSize
              orderProductId: $orderProductId
              worksheetDetails: $worksheetDetails
            )
          }
        `,
        variables: {
          worksheetNo: this.worksheetNo,
          batchId: this._selectedOrderProduct?.batchId,
          productId: this._selectedOrderProduct?.product?.id,
          productDetailId: this._selectedOrderProduct?.productDetail?.id,
          packingType: this._selectedOrderProduct?.packingType,
          packingSize: this._selectedOrderProduct?.packingSize,
          orderProductId: this._selectedOrderProduct?.id,
          worksheetDetails: this._composeWorksheetDetails()
        }
      })

      if (!response.errors) {
        await this.fetchOrderInventories({ page: 1, limit: 9999999 })
        this._showToast({ message: i18next.t('text.reassignment_done') })
      }
    } catch (e) {
      this._showToast(e)
      return
    }
  }

  _composeWorksheetDetails() {
    return this.orderInventoryGrist.dirtyData.records
      .filter(record => record.releaseQty && record.releaseUomValue)
      .map(record => {
        return {
          targetInventory: {
            inventory: { id: record.inventory.id },
            product: { id: record.product.id },
            releaseQty: record.releaseQty,
            releaseUomValue: record.releaseUomValue,
            type: ORDER_TYPES.RELEASE_OF_GOODS.value,
            uom: record.uom
          },
          targetProduct: {
            id: this._selectedOrderProduct?.id
          }
        }
      })
  }

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

window.customElements.define('inventory-reassign-popup', InventoryReassignPopup)
