import '@things-factory/barcode-ui'
import { MultiColumnFormStyles, SingleColumnFormStyles } from '@things-factory/form-ui'
import '@things-factory/grist-ui'
import { i18next, localize } from '@things-factory/i18n-base'
import { openPopup } from '@things-factory/layout-base'
import { client, CustomAlert, PageView, store } from '@things-factory/shell'
import { CommonButtonStyles } from '@things-factory/styles'
import { isMobileDevice } from '@things-factory/utils'
import gql from 'graphql-tag'
import { css, html } from 'lit-element'
import { connect } from 'pwa-helpers/connect-mixin.js'
import { getCodeByName } from '@things-factory/code-base'
import { fetchSettingRule } from '../../fetch-setting-value'
import { CARTON, LOT } from '../constants'
import '../inbound/select-location-popup'

const INVENTORY_TYPES = { LOT, CARTON }
class TransferInventory extends connect(store)(localize(i18next)(PageView)) {
  static get properties() {
    return {
      _palletId: String,
      _cartonId: String,
      _requireNewId: Boolean,
      _selectedInventory: Object,
      refInventoryType: String,
      _data: Object,
      _gristConfig: Object,
      _isExecuting: Boolean,
      _showTransferForm: Boolean,
      _showReasonField: Boolean,
      _showRemarkField: Boolean,
      _toLocationData: Object,
      _transferCodes: Array,
      _locations: Array,
      _locationRecommendationChecked: Boolean
    }
  }

  static get styles() {
    return [
      MultiColumnFormStyles,
      SingleColumnFormStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow: auto;
        }

        .grist {
          min-height: 180px;
          background-color: var(--main-section-background-color);
          display: flex;
          flex: 1;
          overflow: auto;
        }

        data-grist {
          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 {
          grid-column: span 12 / auto;
          text-align: center;
        }

        .button-container > button {
          background-color: var(--button-background-color);
          border: var(--button-border);
          border-radius: var(--button-border-radius);
          padding: var(--button-padding);
          color: var(--button-color);
          font: var(--button-font);
          text-transform: var(--button-text-transform);
        }

        .input-section {
          flex: 1;
          display: flex;
        }

        .left-column {
          flex: 1;
          display: flex;
          flex-direction: column;
        }

        .right-column {
          flex: 1;
          display: flex;
          flex-direction: column;
        }

        .content-title {
          font-size: var(--fontsize-medium) !important;
          color: var(--title-text-color) !important;
        }

        .content {
          font-size: 14px !important;
          font-weight: bold !important;
          color: var(--primary-color) !important;
          margin-botton: 5px;
        }

        /* Mobile form styles - matching unload-product design */
        .mobile-form {
          display: flex;
          flex-direction: column;
          gap: 10px;
          padding: 8px 0;
        }
        .mobile-form fieldset {
          display: flex;
          flex-direction: column;
          align-items: flex-start !important;
          border: none;
          margin: 0;
          padding: 0;
          width: 100%;
          box-sizing: border-box;
        }
        .mobile-form label {
          display: block;
          grid-column: unset !important;
          text-align: left !important;
          align-self: flex-start !important;
          margin-bottom: 4px;
          color: #333;
          font-weight: bold;
          font-size: 14px;
          width: 100%;
          text-transform: capitalize;
        }
        .mobile-form select,
        .mobile-form input[type="text"],
        .mobile-form input[type="date"] {
          grid-column: unset !important;
          width: 100%;
          max-width: 100%;
          height: 24px;
          min-height: 24px;
          border: 1px solid rgba(0, 0, 0, 0.2);
          border-radius: 4px;
          padding: 4px 8px;
          font-size: 12px;
          background-color: white;
          box-sizing: border-box;
        }
        .mobile-form input[type="number"] {
          grid-column: unset !important;
          width: 100%;
          max-width: 100%;
          height: 24px;
          min-height: 24px;
          border: 1px solid rgba(0, 0, 0, 0.2);
          border-radius: 4px;
          padding: 4px 8px;
          padding-right: 24px;
          font-size: 12px;
          background-color: white;
          box-sizing: border-box;
          -moz-appearance: textfield;
        }
        .mobile-form input[type="number"]::-webkit-inner-spin-button,
        .mobile-form input[type="number"]::-webkit-outer-spin-button {
          opacity: 1;
          height: 16px;
        }
        .mobile-form select:focus,
        .mobile-form input:focus {
          outline: none;
          border-color: #017E7F;
        }
        .mobile-form [custom-input] {
          grid-column: unset !important;
          width: 100%;
          box-sizing: border-box;
          border: var(--input-field-border, 1px solid rgba(0, 0, 0, 0.2));
          border-radius: var(--input-field-border-radius, 4px);
        }
        .mobile-form barcode-scanable-input {
          width: 100%;
          max-width: 100%;
          box-sizing: border-box;
          min-width: 0;
          height: 24px;
          min-height: 24px;
        }
        .mobile-form input[disabled] {
          background-color: #f5f5f5;
          cursor: not-allowed;
        }
        .mobile-form .side-by-side-row {
          display: flex;
          flex-direction: row;
          gap: 10px;
        }
        .mobile-form .side-by-side-row fieldset {
          flex: 1;
          min-width: 0;
        }
        /* End of mobile form styles */

        /* Mobile info section */
        .mobile-info-section {
          padding: 8px 8px 12px 8px;
          /* border-bottom: 1px solid #017e7f; */
          margin-bottom: 4px;
          background-color: #F5F7FB;
        }

        .mobile-info-row {
          display: flex;
          flex-direction: row;
          align-items: center;
          padding: 3px 0;
        }

        .mobile-info-label {
          font-weight: bold;
          min-width: 130px;
          color: #3a5877;
          font-size: 13px;
          text-transform: capitalize;
        }

        .mobile-info-value {
          flex: 1;
          color: var(--primary-color);
          font-size: 13px;
        }

        .mobile-section-title {
          color: #017e7f;
          font-weight: bold;
          font-size: 14px;
          margin: 12px 0 0 0;
          padding: 6px 0;
          border-bottom: 1px solid #017e7f;
        }

        form#input-form.mobile-form {
          background-color: #ffffff;
          padding: 8px;
        }
      `
    ]
  }

  get context() {
    var actions = []

    if (isMobileDevice()) {
      if (this._showTransferForm) {
        actions.push({
          title: i18next.t('button.transfer'),
          action: this._onMobileTransfer.bind(this),
          ...CommonButtonStyles.transfer,
          emphasis: { raised: true }
        })
        actions.push({
          title: i18next.t('button.back'),
          action: this._onMobileBack.bind(this),
          ...CommonButtonStyles.back
        })
      } else if (this._selectedInventory) {
        actions.push({
          title: i18next.t('button.select'),
          action: this._onMobileSelect.bind(this),
          ...CommonButtonStyles.save
        })
      }
    } else {
      if (this._palletId || this._cartonId) {
        actions.push({
          title: i18next.t('button.done'),
          action: this.done.bind(this)
        })
      }
    }

    return {
      title: i18next.t('title.transfer_inventory'),
      actions,
      help: 'operato-wms/adjustment/transfer-inventory'
    }
  }

  get infoForm() {
    return this.shadowRoot.querySelector('form#info-form')
  }

  get inputForm() {
    return this.shadowRoot.querySelector('form#input-form')
  }

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

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

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

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

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

  // get fromLocationNameInput() {
  //   return this.shadowRoot.querySelector('input[name=fromLocationName]')
  // }

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

  get reasonSelect() {
    return this.shadowRoot.querySelector('select[name=reason]')
  }

  get remarkTextarea() {
    return this.shadowRoot.querySelector('textarea[name=remark]')
  }

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

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

  focusOnPalletInput() {
    setTimeout(() => this.palletInput.focus(), 100)
  }

  focusOnCartonInput() {
    setTimeout(() => this.cartonInput.focus(), 100)
  }

  focusOnToLocationInput() {
    setTimeout(() => this.toLocationNameInput.focus(), 100)
  }

  focusOnNewLotInput() {
    if (this.newLotInput) setTimeout(() => this.newLotInput.focus(), 100)
  }

  focusOnNewCartonInput() {
    if (this.newCartonInput) setTimeout(() => this.newCartonInput.focus(), 100)
  }

  render() {
    const isMobile = isMobileDevice()
    return html`
      ${!isMobile
        ? html`
            <form id="info-form" class="multi-column-form">
              <fieldset>
                <label>${i18next.t('label.inventory_type')}</label>
                <select name="inventoryType" @change="${e => this.inventoryTypeChangeHandler(e.currentTarget.value)}">
                  ${Object.keys(INVENTORY_TYPES).map(key =>
                    this.refInventoryType === INVENTORY_TYPES[key].value
                      ? html`
                          <option value="${INVENTORY_TYPES[key].value}" selected>
                            ${i18next.t(`label.${INVENTORY_TYPES[key].name}`)}
                          </option>
                        `
                      : html`
                          <option value="${INVENTORY_TYPES[key].value}">
                            ${i18next.t(`label.${INVENTORY_TYPES[key].name}`)}
                          </option>
                        `
                  )}
                </select>

                ${this.refInventoryType === INVENTORY_TYPES.LOT.value
                  ? html`
                      <label>${i18next.t('label.id')}</label>
                      <barcode-scanable-input
                        name="palletId"
                        custom-input
                        @keypress="${e => {
                          if (e.keyCode === 13) {
                            e.preventDefault()
                            if (this.palletInput.value) {
                              this._palletId = this.palletInput.value
                            }
                            this.fetchInventory()
                          }
                        }}"
                      ></barcode-scanable-input>
                    `
                  : html`
                      <label>${i18next.t('label.id')}</label>
                      <barcode-scanable-input
                        name="cartonId"
                        custom-input
                        @keypress="${e => {
                          if (e.keyCode === 13) {
                            e.preventDefault()
                            if (this.cartonInput.value) {
                              this._cartonId = this.cartonInput.value
                            }
                            this.fetchInventory()
                          }
                        }}"
                      ></barcode-scanable-input>
                    `}
              </fieldset>
              <fieldset>
                  <label>${i18next.t('label.product_info')}</label>
                  <barcode-scanable-input
                    name="productInfo"
                    custom-input
                    @keypress="${e => {
                      if (e.keyCode === 13) {
                        e.preventDefault()
                        this.fetchInventory()
                      }
                    }}"
                  ></barcode-scanable-input>

                  <label>${i18next.t('label.location')}</label>
                  <barcode-scanable-input
                    name="searchLocation"
                    custom-input
                    @keypress="${e => {
                      if (e.keyCode === 13) {
                        e.preventDefault()
                        this.fetchInventory()
                      }
                    }}"
                  ></barcode-scanable-input>
              </fieldset>
            </form>

            <div class="grist">
              <data-grist
                .mode=${'GRID'}
                .config=${this._gristConfig}
                .data=${this._data}
              ></data-grist>
            </div>

            <div class="input-section">
              <div class="left-column">
                <div class="single-column-form">
                  <fieldset>
                    <label class="content-title">${this.refInventoryType === INVENTORY_TYPES.LOT.value ? i18next.t('label.lot_id') : i18next.t('label.carton_id')}</label>
                    <label class="content">${this.refInventoryType === INVENTORY_TYPES.LOT.value ? this?._selectedInventory?.palletId || '-' : this?._selectedInventory?.cartonId || '-'}</label>

                    <label class="content-title">${i18next.t('label.from_location')}</label>
                    <label class="content">${this?._selectedInventory?.location?.name || '-'}</label>

                    <label class="content-title">${i18next.t('label.product')}</label>
                    <label class="content"
                      >${this?._selectedInventory?.product
                        ? '(' + this._selectedInventory.product.sku + ') ' + this?._selectedInventory?.product?.name
                        : '-'}</label
                    >
                    <label class="content-title">${i18next.t('label.packing_type')}</label>
                    <label class="content">${this?._selectedInventory?.packingType || '-'}</label>

                    <label class="content-title">${i18next.t('label.qty')}</label>
                    <label class="content">${(this?._selectedInventory?.qty || 0).toString()}</label>

                    <label class="content-title">${i18next.t('label.reserve_qty')}</label>
                    <label class="content">${(this?._selectedInventory?.lockedQty || 0).toString()}</label>

                    <label class="content-title">${i18next.t('label.available_qty')}</label>
                    <label class="content">${(this?._selectedInventory?.availableQty || 0).toString()}</label>
                  </fieldset>
                </div>
              </div>
              <div class="right-column">
                <form id="input-form" class="single-column-form">
                  <fieldset>
                    <label class="content-title">${i18next.t('label.transfer_qty')}</label>
                    <input
                      type="number"
                      name="qty"
                      min="0"
                      @change="${e => {
                        let qtyInputValue = parseFloat(this.qtyInput.value) || null
                        if (!Number.isInteger(parseFloat(this.qtyInput.value))) {
                          this.qtyInput.value = qtyInputValue
                        }
                        if (qtyInputValue < 0) {
                          this.qtyInput.value = 0
                        }
                        if (this._selectedInventory) {
                          if (this._selectedInventory.availableQty >= qtyInputValue) {
                            this._requireNewId = true
                          } else {
                            if (qtyInputValue > this._selectedInventory.availableQty) {
                              this.qtyInput.value = null
                              this.showToast({ message: 'Transferred quantity cannot be more than available quantity' })
                            }
                            this._requireNewId = false
                          }
                        }
                      }}"
                      @keypress="${e => {
                        if (e.keyCode === 13) {
                          e.preventDefault()
                          if (parseFloat(this.qtyInput.value) < 0) {
                            this.qtyInput.value = 0
                          } else if (this.qtyInput.value && this.toLocationNameInput.value === '') {
                            this.focusOnToLocationInput()
                          }
                        }
                      }}"
                    />

                    <label class="content-title">${i18next.t('label.to_location')}</label>
                    <barcode-scanable-input
                      name="toLocationName"
                      custom-input
                      @keypress="${this._handleToLocationEnter.bind(this)}"
                      @input="${() => { this._locationRecommendationChecked = false }}"
                    ></barcode-scanable-input>

                    ${this.refInventoryType === INVENTORY_TYPES.LOT.value
                      ? this._requireNewId
                        ? html`
                            <label class="content-title">${i18next.t('label.new_lot_id')}</label>
                            <barcode-scanable-input
                              name="newLotId"
                              custom-input
                              @keypress="${e => {
                                if (e.keyCode === 13) {
                                  e.preventDefault()
                                  this.transferInventory(e)
                                }
                              }}"
                            ></barcode-scanable-input>
                          `
                        : ``
                      : html`
                          <label class="content-title">${i18next.t('label.new_carton_id')}</label>
                          <barcode-scanable-input
                            name="newCartonId"
                            custom-input
                            @keypress="${e => {
                              if (e.keyCode === 13) {
                                e.preventDefault()
                                this.transferInventory(e)
                              }
                            }}"
                          ></barcode-scanable-input>
                        `}

                    ${this._showReasonField ? html`
                      <label class="content-title">${i18next.t('label.reason')}</label>
                      <select name="reason" @change="${e => {
                        this._showRemarkField = e.currentTarget.value.toUpperCase() === 'OTHERS'
                      }}">
                        <option value=""></option>
                        ${(this._transferCodes || []).map(code => html`
                          <option value="${code.name}">${code.description || code.name}</option>
                        `)}
                      </select>
                    ` : ''}

                    ${this._showRemarkField ? html`
                      <label class="content-title">${i18next.t('label.remark')}</label>
                      <textarea name="remark" rows="3"></textarea>
                    ` : ''}

                    <div class="button-container">
                      <button @click=${this.transferInventory.bind(this)}>${i18next.t('button.transfer')}</button>
                    </div>
                  </fieldset>
                </form>
              </div>
            </div>
          `
        : this._showTransferForm
        ? html`
            <div class="mobile-info-section">
              <div class="mobile-info-row">
                <div class="mobile-info-label">${this.refInventoryType === INVENTORY_TYPES.LOT.value ? i18next.t('label.lot_id') : i18next.t('label.carton_id')}</div>
                <div class="mobile-info-value">${this.refInventoryType === INVENTORY_TYPES.LOT.value ? this._selectedInventory?.palletId || '-' : this._selectedInventory?.cartonId || '-'}</div>
              </div>
              <div class="mobile-info-row">
                <div class="mobile-info-label">${i18next.t('label.product')}</div>
                <div class="mobile-info-value">${this._selectedInventory?.product ? '(' + this._selectedInventory.product.sku + ') ' + this._selectedInventory.product.name : '-'}</div>
              </div>
              <div class="mobile-info-row">
                <div class="mobile-info-label">${i18next.t('label.from_location')}</div>
                <div class="mobile-info-value">${this._selectedInventory?.location?.name || '-'}</div>
              </div>
              <div class="mobile-info-row">
                <div class="mobile-info-label">${i18next.t('label.packing_type')}</div>
                <div class="mobile-info-value">${this._selectedInventory?.packingType || '-'}</div>
              </div>
              <div class="mobile-info-row">
                <div class="mobile-info-label">${i18next.t('label.qty')}</div>
                <div class="mobile-info-value">${(this._selectedInventory?.qty || 0).toString()}</div>
              </div>
              <div class="mobile-info-row">
                <div class="mobile-info-label">${i18next.t('label.reserve_qty')}</div>
                <div class="mobile-info-value">${(this._selectedInventory?.lockedQty || 0).toString()}</div>
              </div>
              <div class="mobile-info-row">
                <div class="mobile-info-label">${i18next.t('label.available_qty')}</div>
                <div class="mobile-info-value">${(this._selectedInventory?.availableQty || 0).toString()}</div>
              </div>
            </div>

            <form id="input-form" class="mobile-form">
              <fieldset>
                <label>${i18next.t('label.transfer_qty')}</label>
                <input
                  type="number"
                  name="qty"
                  min="0"
                  @change="${_ => {
                    let qtyInputValue = parseFloat(this.qtyInput.value) || null
                    if (!Number.isInteger(parseFloat(this.qtyInput.value))) {
                      this.qtyInput.value = qtyInputValue
                    }
                    if (qtyInputValue < 0) {
                      this.qtyInput.value = 0
                    }
                    if (this._selectedInventory) {
                      if (this._selectedInventory.availableQty >= qtyInputValue) {
                        this._requireNewId = true
                      } else {
                        if (qtyInputValue > this._selectedInventory.availableQty) {
                          this.qtyInput.value = null
                          this.showToast({ message: 'Transferred quantity cannot be more than available quantity' })
                        }
                        this._requireNewId = false
                      }
                    }
                  }}"
                  @keypress="${e => {
                    if (e.keyCode === 13) {
                      e.preventDefault()
                      if (parseFloat(this.qtyInput.value) < 0) {
                        this.qtyInput.value = 0
                      } else if (this.qtyInput.value && this.toLocationNameInput.value === '') {
                        this.focusOnToLocationInput()
                      }
                    }
                  }}"
                />
              </fieldset>

              <fieldset>
                <label>${i18next.t('label.to_location')}</label>
                <barcode-scanable-input
                  name="toLocationName"
                  custom-input
                  @keypress="${this._handleToLocationEnter.bind(this)}"
                  @input="${() => { this._locationRecommendationChecked = false }}"
                ></barcode-scanable-input>
              </fieldset>

              ${this.refInventoryType === INVENTORY_TYPES.LOT.value
                ? this._requireNewId
                  ? html`
                      <fieldset>
                        <label>${i18next.t('label.new_lot_id')}</label>
                        <barcode-scanable-input
                          name="newLotId"
                          custom-input
                          @keypress="${e => {
                            if (e.keyCode === 13) {
                              e.preventDefault()
                              this.transferInventory(e)
                            }
                          }}"
                        ></barcode-scanable-input>
                      </fieldset>
                      `
                  : ``
                : html`
                    <fieldset>
                      <label>${i18next.t('label.new_carton_id')}</label>
                      <barcode-scanable-input
                        name="newCartonId"
                        custom-input
                        @keypress="${e => {
                          if (e.keyCode === 13) {
                            e.preventDefault()
                            this.transferInventory(e)
                          }
                        }}"
                      ></barcode-scanable-input>
                    </fieldset>
                  `}

              ${this._showReasonField ? html`
                <fieldset>
                  <label>${i18next.t('label.reason')}</label>
                  <select name="reason" @change="${e => {
                    this._showRemarkField = e.currentTarget.value.toUpperCase() === 'OTHERS'
                  }}">
                    <option value=""></option>
                    ${(this._transferCodes || []).map(code => html`
                      <option value="${code.name}">${code.description || code.name}</option>
                    `)}
                  </select>
                </fieldset>
              ` : ''}

              ${this._showRemarkField ? html`
                <fieldset>
                  <label>${i18next.t('label.remark')}</label>
                  <textarea name="remark" rows="3"></textarea>
                </fieldset>
              ` : ''}
            </form>
          `
        : html`
            <form id="info-form" class="mobile-form">
              <fieldset class="side-by-side-row">
                <fieldset>
                  <label>${i18next.t('label.inventory_type')}</label>
                  <select name="inventoryType" @change="${e => this.inventoryTypeChangeHandler(e.currentTarget.value)}">
                    ${Object.keys(INVENTORY_TYPES).map(key =>
                      this.refInventoryType === INVENTORY_TYPES[key].value
                        ? html`
                            <option value="${INVENTORY_TYPES[key].value}" selected>
                              ${i18next.t(`label.${INVENTORY_TYPES[key].name}`)}
                            </option>
                          `
                        : html`
                            <option value="${INVENTORY_TYPES[key].value}">
                              ${i18next.t(`label.${INVENTORY_TYPES[key].name}`)}
                            </option>
                          `
                    )}
                  </select>
                </fieldset>
                <fieldset>
                  <label>${i18next.t('label.id')}</label>
                  ${this.refInventoryType === INVENTORY_TYPES.LOT.value
                    ? html`
                        <barcode-scanable-input
                          name="palletId"
                          custom-input
                          @keypress="${e => {
                            if (e.keyCode === 13) {
                              e.preventDefault()
                              if (this.palletInput.value) {
                                this._palletId = this.palletInput.value
                              }
                              this.fetchInventory()
                            }
                          }}"
                        ></barcode-scanable-input>
                      `
                    : html`
                        <barcode-scanable-input
                          name="cartonId"
                          custom-input
                          @keypress="${e => {
                            if (e.keyCode === 13) {
                              e.preventDefault()
                              if (this.cartonInput.value) {
                                this._cartonId = this.cartonInput.value
                              }
                              this.fetchInventory()
                            }
                          }}"
                        ></barcode-scanable-input>
                      `}
                </fieldset>
              </fieldset>
              <fieldset class="side-by-side-row">
                <fieldset>
                  <label>${i18next.t('label.product_info')}</label>
                  <barcode-scanable-input
                    name="productInfo"
                    custom-input
                    @keypress="${e => {
                      if (e.keyCode === 13) {
                        e.preventDefault()
                        this.fetchInventory()
                      }
                    }}"
                  ></barcode-scanable-input>
                </fieldset>
                <fieldset>
                  <label>${i18next.t('label.location')}</label>
                  <barcode-scanable-input
                    name="searchLocation"
                    custom-input
                    @keypress="${e => {
                      if (e.keyCode === 13) {
                        e.preventDefault()
                        this.fetchInventory()
                      }
                    }}"
                  ></barcode-scanable-input>
                </fieldset>
              </fieldset>
            </form>

            <div class="grist">
              <data-grist
                .mode=${'LIST'}
                .config=${this._gristConfig}
                .data=${this._data}
                .selectedRecords=${this._selectedInventory ? [this._selectedInventory] : []}
              ></data-grist>
            </div>
          `}
    `
  }

  constructor() {
    super()
    this._isExecuting = false
  }

  async pageInitialized() {
    this._transferCodes = await getCodeByName('TRANSFER_CODES')

    const [locationRecommendationLevel, stackingOptionLimitStr] = await Promise.all([
      fetchSettingRule('location-recommendation-level'),
      fetchSettingRule('stacking-option-limit')
    ])
    this._locationRecommendationLevel = (locationRecommendationLevel || '').toUpperCase().trim()
    try {
      const parsed = JSON.parse(stackingOptionLimitStr || '{}')
      this._stackingOptionLimit = { min: Number(parsed.Min) || 1, max: Number(parsed.Max) || 1 }
    } catch {
      this._stackingOptionLimit = { min: 1, max: 1 }
    }

    await this._fetchLocations()
    this.refInventoryType = INVENTORY_TYPES.LOT.value
    this._gristConfig = {
      list: {
        fields: [
          'sku',
          'product',
          'cartonId',
          'palletId',
          'location',
          'batchId',
          'packingType',
          'packingSize',
          'qty',
          'lockedQty',
          'availableQty',
          'expirationDate'
        ]
      },
      pagination: { infinite: true },
      rows: {
        appendable: false,
        handlers: {
          click: async (columns, data, column, record, rowIndex) => {
            try {
              if (this._selectedInventory) this._selectedInventory['__selected__'] = false
              record['__selected__'] = true
              this._selectedInventory = record
              this._resetReasonFields()
              this.updateContext()
            } catch (ex) {
              console.log(ex)
            } finally {
            }
          }
        }
      },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'string',
          name: 'sku',
          label: true,
          header: i18next.t('field.sku'),
          width: 150
        },
        {
          type: 'object',
          name: 'product',
          label: true,
          header: i18next.t('field.product'),
          width: 200
        },
        {
          type: 'string',
          name: 'cartonId',
          label: true,
          header: i18next.t('field.carton_id'),
          width: 150
        },
        {
          type: 'string',
          name: 'palletId',
          label: true,
          header: i18next.t('field.lot_id'),
          width: 150
        },
        {
          type: 'object',
          name: 'location',
          label: true,
          header: i18next.t('field.location'),
          width: 200
        },
        {
          type: 'string',
          name: 'batchId',
          label: true,
          header: i18next.t('field.batch_id'),
          width: 150
        },
        {
          type: 'string',
          name: 'packingType',
          label: true,
          header: i18next.t('field.packing'),
          width: 150
        },
        {
          type: 'number',
          name: 'packingSize',
          label: true,
          header: i18next.t('field.size'),
          width: 80
        },
        {
          type: 'float',
          name: 'qty',
          label: true,
          header: i18next.t('field.qty'),
          width: 60
        },
        {
          type: 'float',
          name: 'lockedQty',
          label: true,
          header: i18next.t('field.reserve_qty'),
          width: 60
        },
        {
          type: 'float',
          name: 'availableQty',
          label: true,
          header: i18next.t('field.available_qty'),
          width: 60
        },
        {
          type: 'date',
          name: 'expirationDate',
          header: i18next.t('field.exp_date'),
          label: true,
          width: 60
        }
      ]
    }

    this.clearView()
  }

  inventoryTypeChangeHandler(currentType) {
    this.clearView()

    this.refInventoryType = currentType

    if (this.refInventoryType === INVENTORY_TYPES.LOT.value) this.focusOnPalletInput()
    else this.focusOnCartonInput()
  }

  _resetReasonFields() {
    this._showReasonField = false
    this._showRemarkField = false
    this._locationRecommendationChecked = false
    if (this.reasonSelect) this.reasonSelect.value = ''
    if (this.remarkTextarea) this.remarkTextarea.value = ''
  }

  async fetchInventory() {
    try {
      this._resetReasonFields()
      let filters = []

      const idValue =
        this.refInventoryType === INVENTORY_TYPES.LOT.value ? this.palletInput?.value : this.cartonInput?.value

      if (idValue) {
        const idField = this.refInventoryType === INVENTORY_TYPES.LOT.value ? 'palletId' : 'cartonId'
        filters.push({ name: idField, operator: 'eq', value: idValue })
      }

      const productInfoValue = this.productInfoInput?.value?.trim()
      const searchLocationValue = this.searchLocationInput?.value?.trim()

      if (searchLocationValue) {
        await this._fetchLocations()
        const locationExists = (this._locations || []).some(l => l.name === searchLocationValue)
        if (!locationExists) {
          throw new Error(i18next.t('text.location_not_found'))
        }
        filters.push({ name: 'locationName', operator: 'eq', value: searchLocationValue })
      }

      if (productInfoValue) {
        filters.push({ name: 'productInfo', operator: 'like', value: productInfoValue })
      }

      if (filters.length === 0) return

      filters.push({ name: 'status', operator: 'eq', value: 'STORED' })
      filters.push({ name: 'refInventoryType', operator: 'eq', value: this.refInventoryType })

      const response = await client.query({
        query: gql`
          query inventories($filters: [Filter!]) {
            inventories(filters: $filters) {
              items {
                id
                palletId
                cartonId
                batchId
                batchIdRef
                packingType
                packingSize
                product {
                  id
                  sku
                  name
                  description
                  allowStackingOption
                }
                qty
                lockedQty
                location {
                  id
                  name
                  description
                }
                expirationDate
                remark
              }
              total
            }
          }
        `,
        variables: { filters }
      })

      if (!response.errors) {
        if (response.data.inventories.total == 0) {
          if (idValue && !productInfoValue && !searchLocationValue) {
            if (this.refInventoryType === INVENTORY_TYPES.LOT.value) {
              this.focusOnPalletInput()
              throw new Error(i18next.t('text.lot_id_not_found'))
            } else {
              this.focusOnCartonInput()
              throw new Error(i18next.t('text.carton_id_not_found'))
            }
          } else if ((productInfoValue && !idValue && !searchLocationValue) || (searchLocationValue && !idValue && !productInfoValue)) {
            throw new Error(i18next.t('text.there_is_no_inventory_for_the_product'))
          }

          this._selectedInventory = null
        }

        this._data = {
          records: response.data.inventories.items.map(record => {
            return {
              ...record,
              sku: record.product.sku,
              availableQty: record.qty - (record.lockedQty > 0 ? record.lockedQty : 0)
            }
          })
        }

        if (this.refInventoryType === INVENTORY_TYPES.LOT.value && !productInfoValue && !searchLocationValue && response.data.inventories.total > 0) {
          this._selectedInventory = this._data.records[0]
        }

        this.updateContext()
      }
    } catch (e) {
      this.clearView()
      if (this.refInventoryType === INVENTORY_TYPES.LOT.value) this.focusOnPalletInput()
      else this.focusOnCartonInput()
      this.showToast(e)
    }
  }

  async transferInventory(e) {
    try {
      e.stopPropagation()
      e.preventDefault()

      if (this._isExecuting) throw new Error(i18next.t('text.please_wait_for_current_process_to_be_completed'))
      this._isExecuting = true
      this._validate()

      if (!this._locationRecommendationChecked) {
        const locationName = this.toLocationNameInput.value
        const confirmed = await this._checkLocationRecommendation(locationName)
        if (!confirmed) {
          this.toLocationNameInput.value = ''
          return
        }
        this._locationRecommendationChecked = true
      }

      const result = await CustomAlert({
        title: i18next.t('title.are_you_sure'),
        text: i18next.t('text.transfer_inventory_to_different_location'),
        confirmButton: { text: i18next.t('button.confirm') },
        cancelButton: { text: i18next.t('button.cancel') }
      })

      if (!result.value) {
        return
      }

      let variables = {
        originPalletId: this._selectedInventory.palletId,
        palletId: this.refInventoryType === INVENTORY_TYPES.LOT.value ? this.newLotInput?.value : null,
        cartonId: this.refInventoryType === INVENTORY_TYPES.CARTON.value ? this.newCartonInput?.value : null,
        fromLocationName: this._selectedInventory.location.name,
        toLocationName: this.toLocationNameInput.value,
        qty: parseFloat(this.qtyInput.value),
        reason: this._showReasonField ? this.reasonSelect?.value || null : null,
        remark: this._showRemarkField ? this.remarkTextarea?.value?.trim() || null : null
      }

      const response = await client.mutate({
        mutation: gql`
          mutation inventoryTransfer(
            $originPalletId: String!
            $palletId: String
            $cartonId: String
            $fromLocationName: String!
            $toLocationName: String!
            $qty: Float!
            $reason: String
            $remark: String
          ) {
            inventoryTransfer(
              originPalletId: $originPalletId
              palletId: $palletId
              cartonId: $cartonId
              fromLocationName: $fromLocationName
              toLocationName: $toLocationName
              qty: $qty
              reason: $reason
              remark: $remark
            )
          }
        `,
        variables
      })

      if (!response.errors) {
        let id = this.refInventoryType === INVENTORY_TYPES.LOT.value ? this._palletId : this._cartonId
        this.showToast({ message: i18next.t('text.transfer_location_completed') })
        this.clearView()
        // this.fetchInventory(id)
        this.updateContext()
      }
    } catch (e) {
      // HANDLE EDGE SCENARIOS
      if (e.message === 'Please select a reason') {
        this._showReasonField = true
        this.reasonSelect?.focus()
      } else if (e.message === 'Please enter a remark') {
        this._showReasonField = true
        this._showRemarkField = true
        this.remarkTextarea?.focus()
      }
      this.showToast(e)
    } finally {
      this._isExecuting = false
    }
  }

  _validate() {
    if (!this._selectedInventory) {
      throw new Error(i18next.t('text.please_select_an_inventory'))
    }

    if (!(this._selectedInventory.availableQty > 0)) {
      throw new Error(i18next.t('text.not_enough_available_qty'))
    }

    if (!parseFloat(this.qtyInput?.value || 0) > 0) {
      throw new Error(i18next.t('text.please_enter_transfer_qty'))
    } else {
      const qty = this.qtyInput?.value
      if ((qty.toString().split('.')[1] || '').length > 3) {
        throw new Error(i18next.t('text.transfer_qty_cannot_exceed_3_decimal_places'))
      }
    }

    if (!this.toLocationNameInput.value) {
      this.focusOnToLocationInput()
      throw new Error(i18next.t('text.there_is_no_to_location'))
    }

    if (this._selectedInventory?.location?.name == this.toLocationNameInput.value) {
      throw new Error(i18next.t('text.from_location_is_same_as_to_location'))
    }

    // if (this.refInventoryType === INVENTORY_TYPES.CARTON.value && this?.cartonInput?.value.trim() == '') {
    //   throw new Error(i18next.t('text.required_carton_id'))
    // }

    const toLocationName = this.toLocationNameInput.value
    const toLocation = (this._locations || []).find(l => l.name === toLocationName)
    const toIsSpecial = this._isSpecialLocationType(toLocation?.type)

    const fromLocationName = this._selectedInventory?.location?.name
    const fromLocationType = (this._locations || []).find(l => l.name === fromLocationName)?.type
    const fromIsSpecial = this._isSpecialLocationType(fromLocationType)

    if (toIsSpecial !== fromIsSpecial) {
      if (!this.reasonSelect?.value) {
        this._showReasonField = true
        this.reasonSelect?.focus()
        throw new Error(i18next.t('text.please_select_a_reason'))
      }
      if (this.reasonSelect.value.toUpperCase() === 'OTHERS' && !this.remarkTextarea?.value?.trim()) {
        this._showRemarkField = true
        this.remarkTextarea?.focus()
        throw new Error(i18next.t('text.please_enter_a_remark'))
      }
    } else {
      this._showReasonField = false
      this._showRemarkField = false
    }
  }

  done() {
    this.clearView()
    if (this.refInventoryType === INVENTORY_TYPES.LOT.value) {
      this.palletInput.value = ''
      this._palletId = ''
    } else {
      this.cartonInput.value = ''
      this.cartonId = ''
    }
    if (this?.productInfoInput) this.productInfoInput.value = ''
    if (this?.searchLocationInput) this.searchLocationInput.value = ''
  }

  _onMobileSelect() {
    if (!this._selectedInventory) return
    this._resetReasonFields()
    this._showTransferForm = true
    this.updateContext()
  }

  _onMobileBack() {
    this._resetReasonFields()
    this._showTransferForm = false
    this.updateContext()
  }

  _onMobileTransfer() {
    this.transferInventory({ stopPropagation: () => {}, preventDefault: () => {} })
  }

  async _fetchLocations() {
    try {
      const response = await client.query({
        query: gql`
          query {
            locations {
              items {
                id
                name
                type
                status
              }
            }
          }
        `
      })
      if (!response.errors) {
        this._locations = response.data.locations.items
      }
    } catch (e) {
      console.error('Failed to fetch locations', e)
    }
  }

  _handleToLocationEnter(e) {
    if (e.keyCode === 13) {
      e.preventDefault()
      if (this.toLocationNameInput?.value) {
        this._validateAndProceedToLocation()
      }
    }
  }

  async _checkLocationRecommendation(toLocationName) {
    const level = this._locationRecommendationLevel
    if (!level) return true

    const fromSku = this._selectedInventory?.product?.sku

    const response = await client.query({
      query: gql`
        query inventories($filters: [Filter!]) {
          inventories(filters: $filters) {
            items {
              product { sku }
            }
            total
          }
        }
      `,
      variables: {
        filters: [
          { name: 'locationName', operator: 'eq', value: toLocationName },
          { name: 'status', operator: 'eq', value: 'STORED' }
        ]
      }
    })

    if (response.errors) return true

    const { items: inventoriesAtLocation = [], total: countAtLocation = 0 } = response.data.inventories

    let warningMsg = null

    switch (level) {
      case 'LEVEL 1': {
        await this._fetchLocations(); // REFRESH TO GET LATEST
        const toLocation = (this._locations || []).find(l => l.name === toLocationName)
        if (toLocation?.status?.toUpperCase() !== 'EMPTY') {
          warningMsg = i18next.t('text.reminder_location_assigned_to_another_sku')
        }
        break
      }
      case 'LEVEL 2': {
        const hasDifferentSku = inventoriesAtLocation.some(inv => inv.product?.sku !== fromSku)
        if (hasDifferentSku) {
          warningMsg = i18next.t('text.reminder_location_assigned_to_another_sku')
        }
        break
      }
      case 'LEVEL 3': {
        const hasDifferentSku = inventoriesAtLocation.some(inv => inv.product?.sku !== fromSku)
        const allowStacking = this._selectedInventory?.product?.allowStackingOption
        const stackingLimit = allowStacking ? this._stackingOptionLimit?.max : null
        const hitStackingLimit = stackingLimit != null && countAtLocation >= stackingLimit
        if (hasDifferentSku || hitStackingLimit) {
          warningMsg = i18next.t('text.reminder_location_occupied_by_different_sku_or_stacking_capacity')
        }
        break
      }
      default:
        
    }

    if (!warningMsg) return true

    const result = await CustomAlert({
      title: i18next.t('title.reminder'),
      text: warningMsg,
      confirmButton: { text: i18next.t('button.confirm') },
      cancelButton: { text: i18next.t('button.cancel') }
    })

    return result.value
  }

  _isSpecialLocationType(type) {
    const t = type?.toUpperCase()
    return t === 'DAMAGE' || t === 'QUARANTINE'
  }

  async _validateAndProceedToLocation() {
    try {
      const locationName = this.toLocationNameInput.value
      const toLocation = (this._locations || []).find(l => l.name === locationName)

      if (!toLocation) throw new Error(i18next.t('text.location_not_found'))

      if (!this._locationRecommendationChecked) {
        const confirmed = await this._checkLocationRecommendation(locationName)
        if (!confirmed) {
          this.toLocationNameInput.value = ''
          return
        }
        this._locationRecommendationChecked = true
      }

      this._toLocationData = toLocation

      const toIsSpecial = this._isSpecialLocationType(toLocation.type)
      const fromLocationName = this._selectedInventory?.location?.name
      const fromLocationType = (this._locations || []).find(l => l.name === fromLocationName)?.type
      const fromIsSpecial = this._isSpecialLocationType(fromLocationType)
      const requiresReason = toIsSpecial !== fromIsSpecial // FROM SPECIAL LOCATION -> NORMAL || NORMAL -> SPECIAL LOCATION

      if (this.reasonSelect) this.reasonSelect.value = ''
      if (this.remarkTextarea) this.remarkTextarea.value = ''

      if (requiresReason) {
        this._showReasonField = true
        this.reasonSelect?.focus()
        await this.updateComplete
      } else {
        this._showReasonField = false
        this._showRemarkField = false
        if (this.refInventoryType === INVENTORY_TYPES.LOT.value) {
          if (this._requireNewId) {
            this.focusOnNewLotInput()
          } else {
            this.transferInventory({ stopPropagation: () => {}, preventDefault: () => {} })
          }
        } else {
          this.focusOnNewCartonInput()
        }
      }
    } catch (e) {
      this.showToast(e)
    }
  }

  clearView() {
    this.inputForm?.reset()
    this._selectedInventory = null
    this._requireNewId = false
    this._showTransferForm = false
    this._showReasonField = false
    this._showRemarkField = false
    this._toLocationData = null
    this._locationRecommendationChecked = false
    this._data = { records: [] }
    if (this?.toLocationNameInput) this.toLocationNameInput.value = ''
    if (this?.newCartonInput) this.newCartonInput.value = ''
    if (this?.newLotInput) this.newLotInput.value = ''
    this.updateContext()
  }

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

window.customElements.define('transfer-inventory', TransferInventory)
