import '@things-factory/grist-ui'

import gql from 'graphql-tag'
import { css, html, LitElement } from 'lit-element'
import { connect } from 'pwa-helpers/connect-mixin'

import { SingleColumnFormStyles } from '@things-factory/form-ui'
import { i18next, localize } from '@things-factory/i18n-base'
import { client, CustomAlert, store } from '@things-factory/shell'
import { isMobileDevice } from '@things-factory/utils'

import { ARRIVAL_NOTICE, CUSTOMER_RETURN, REPLENISHMENT, WAREHOUSE_RETURN } from '../../constants'

const AVAIL_ORDER_TYPES = { ARRIVAL_NOTICE, CUSTOMER_RETURN, WAREHOUSE_RETURN, REPLENISHMENT }

class UndoPutawayPopup extends connect(store)(localize(i18next)(LitElement)) {
  static get properties() {
    return {
      _autoSelectInventory: Array,
      _selectedInventories: Array,
      config: Object,
      data: Object,
      enableCartonLabel: Boolean,
      enableProductScanning: Boolean,
      replenishmentId: String,
      orderType: String,
      orderNo: String,
      putawayInventories: Array
    }
  }

  constructor() {
    super()
    this._selectedInventories = []
    this._autoSelectInventory = []
  }

  static get styles() {
    return [
      SingleColumnFormStyles,
      css`
        .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);
        }
        .button-container button {
          background-color: var(--button-container-button-background-color);
          border-radius: var(--button-container-button-border-radius);
          height: var(--button-container-button-height);
          border: var(--button-container-button-border);
          margin: var(--button-container-button-margin);

          padding: var(--button-padding);
          color: var(--theme-white-color);
          font: var(--button-font);
          text-transform: var(--button-text-transform);
        }
        .button-container button:hover,
        .button-container button:active {
          background-color: var(--button-background-focus-color);
        }
        data-grist {
          overflow-y: hidden;
          flex: 1;
        }
        .grist {
          display: flex;
          flex-direction: column;
          flex: 1;
          overflow-y: auto;
        }
        :host {
          padding: 10px;
          display: flex;
          flex-direction: column;
          overflow: hidden;
          background-color: white;
        }
      `
    ]
  }

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

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

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

  get lotInput() {
    return this.shadowRoot.querySelector('barcode-scanable-input[name=lotId]').shadowRoot.querySelector('input')
  }

  render() {
    return html`
      <form id="input-form" class="single-column-form">
        <fieldset>
          ${this.enableCartonLabel
            ? html`<label>${i18next.t('label.carton_id')}</label>
                <barcode-scanable-input
                  name="cartonId"
                  custom-input
                  @keypress="${e => {
                    this._populateTargetedInventory(e)
                  }}"
                ></barcode-scanable-input>`
            : html`<label>${i18next.t('label.lot_id')}</label>
                <barcode-scanable-input
                  name="lotId"
                  custom-input
                  @keypress="${e => {
                    this._populateTargetedInventory(e)
                  }}"
                ></barcode-scanable-input>`}
        </fieldset>
      </form>

      <div class="grist">
        <data-grist
          id="grist"
          .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
          .config=${this.config}
          .data="${this.data}"
        ></data-grist>
      </div>

      <div class="button-container">
        <mwc-button raised @click="${this._undoPutaway.bind(this)}" label="${i18next.t('button.undo')}"></mwc-button>
      </div>
    `
  }

  firstUpdated() {
    this.config = {
      pagination: { infinite: true },
      rows: { selectable: { multiple: true }, appendable: false },
      list: { fields: ['palletId', 'cartonId', 'batchId', 'product', 'packingType', 'packingSize', 'qty', 'status'] },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        { type: 'gutter', gutterName: 'row-selector', multiple: true },
        { name: 'id', hidden: true },
        {
          type: 'string',
          name: 'palletId',
          label: true,
          header: i18next.t('field.lot_id'),
          width: 150
        },
        {
          type: 'string',
          name: 'cartonId',
          label: true,
          header: i18next.t('field.carton_id'),
          width: 150
        },
        {
          type: 'string',
          name: 'batchId',
          label: true,
          header: i18next.t('field.batch_id'),
          width: 150
        },
        {
          type: 'object',
          name: 'product',
          label: true,
          header: i18next.t('field.product'),
          width: 250
        },
        {
          type: 'string',
          name: 'packingType',
          label: true,
          header: i18next.t('field.packing_type'),
          width: 120
        },
        {
          type: 'integer',
          name: 'packingSize',
          label: true,
          header: i18next.t('field.packing_size'),
          width: 100
        },
        {
          type: 'float',
          name: 'qty',
          label: true,
          header: i18next.t('field.qty'),
          width: 100
        },
        {
          type: 'string',
          name: 'status',
          label: true,
          header: i18next.t('field.status'),
          width: 120
        }
      ]
    }

    if (this.enableCartonLabel) {
      this._focusOnCartonInput()
    } else {
      this._focusOnLotInput()
    }
  }

  async _undoPutaway() {
    try {
      let selectedInventories = []
      selectedInventories = this.dataGrist.selected

      if (!selectedInventories?.length) throw new Error(i18next.t('text.select_at_least_one_inventory_to_undo'))

      this._validateScanInventory()

      let response = {}

      if (this.orderType === AVAIL_ORDER_TYPES.ARRIVAL_NOTICE.value) {
        response = await this._undoArrivalNoticePutaway(selectedInventories)
      } else if (this.orderType === AVAIL_ORDER_TYPES.CUSTOMER_RETURN.value) {
        response = await this._undoCustomerReturnPutaway(selectedInventories)
      } else if (this.orderType === AVAIL_ORDER_TYPES.REPLENISHMENT.value) {
        response = await this._undoReplenishmentPutaway(selectedInventories)
      }

      if (response && !response?.errors) {
        this.dispatchEvent(new CustomEvent('undo-inventory'))
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  async _populateTargetedInventory(e) {
    if (e.keyCode === 13) {
      e.preventDefault()

      let targetedUndoInventories = []

      if (this.enableCartonLabel) {
        if (this.enableProductScanning && this.orderType === AVAIL_ORDER_TYPES.REPLENISHMENT.value) {
          let inventories = await this._getReplenishedInventories()
          const matchedInventories = inventories.filter(inventory => inventory.cartonId === this.cartonInput?.value)

          if (matchedInventories.length > 0) {
            targetedUndoInventories = this.putawayInventories
              .filter(inventory => matchedInventories.some(inv => inventory.cartonId === inv.refInventory?.cartonId))
              .map(inventory => {
                return {
                  ...inventory,
                  newCartonId: matchedInventories[0].cartonId
                }
              })
          } else {
            targetedUndoInventories = []
          }
        } else {
          targetedUndoInventories = this.putawayInventories.filter(
            inventory => inventory.cartonId === this.cartonInput?.value
          )
        }
      } else {
        targetedUndoInventories = this.putawayInventories.filter(
          inventory => inventory.palletId === this.lotInput?.value
        )
      }

      if (!targetedUndoInventories?.length) {
        if (this.enableCartonLabel) {
          this.cartonInput.value = ''
        } else {
          this.lotInput.value = ''
        }
        this._showToast({ message: i18next.t('text.no_matching_putaway_inventory_found') })
      } else {
        this.data = { records: targetedUndoInventories }
        if (targetedUndoInventories?.length == 1) {
          this.data.records[0].__selected__ = true
        }
      }
    }
  }

  async _getReplenishedInventories() {
    const replenishmentId = this.replenishmentId
    const inventoryIds = this.putawayInventories.map(inventory => inventory.inventoryId)

    const response = await client.query({
      query: gql`
        query putawayReplenishmentInventories($replenishmentId: String!, $inventoryId: [String!]!) {
          putawayReplenishmentInventories(replenishmentId: $replenishmentId, inventoryId: $inventoryId) {
            items {
              cartonId
              refInventory {
                cartonId
              }
            }
          }
        }
      `,
      variables: {
        replenishmentId: replenishmentId,
        inventoryId: inventoryIds
      }
    })

    if (!response.errors) {
      return response.data.putawayReplenishmentInventories.items || []
    }
  }

  async _undoArrivalNoticePutaway(selectedInventories) {
    try {
      if (selectedInventories.length > 1) {
        const result = await CustomAlert({
          title: i18next.t('title.are_you_sure'),
          text: i18next.t('text.undo_putaway'),
          confirmButton: { text: i18next.t('button.confirm') },
          cancelButton: { text: i18next.t('button.cancel') }
        })

        if (!result?.value) {
          return
        }
      }

      const response = await client.mutate({
        mutation: gql`
          mutation undoPutaway($worksheetDetailName: [String]!, $palletId: String, $cartonId: String) {
            undoPutaway(worksheetDetailName: $worksheetDetailName, palletId: $palletId, cartonId: $cartonId)
          }
        `,
        variables: {
          worksheetDetailName: selectedInventories.map(inventory => inventory.name),
          palletId: this.enableCartonLabel ? null : selectedInventories[0].palletId,
          cartonId: this.enableCartonLabel ? selectedInventories[0].cartonId : null
        }
      })

      if (!response.errors) {
        return response
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  async _undoCustomerReturnPutaway(selectedInventories) {
    try {
      if (selectedInventories.length > 1) {
        const result = await CustomAlert({
          title: i18next.t('title.are_you_sure'),
          text: i18next.t('text.undo_putaway'),
          confirmButton: { text: i18next.t('button.confirm') },
          cancelButton: { text: i18next.t('button.cancel') }
        })

        if (!result?.value) {
          return
        }
      }

      const response = await client.mutate({
        mutation: gql`
          mutation undoPutawayReturn($worksheetDetailName: [String]!, $palletId: String, $cartonId: String) {
            undoPutawayReturn(worksheetDetailName: $worksheetDetailName, palletId: $palletId, cartonId: $cartonId)
          }
        `,
        variables: {
          worksheetDetailName: selectedInventories.map(inventory => inventory.name),
          palletId: this.enableCartonLabel ? null : selectedInventories[0].palletId,
          cartonId: this.enableCartonLabel ? selectedInventories[0].cartonId : null
        }
      })

      if (!response.errors) {
        return response
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  async _undoReplenishmentPutaway(selectedInventories) {
    try {
      if (selectedInventories.length > 1) {
        const result = await CustomAlert({
          title: i18next.t('title.are_you_sure'),
          text: i18next.t('text.undo_putaway'),
          confirmButton: { text: i18next.t('button.confirm') },
          cancelButton: { text: i18next.t('button.cancel') }
        })

        if (!result?.value) {
          return
        }
      }

      const cartonId = this.enableCartonLabel
        ? this.enableProductScanning
          ? selectedInventories[0].newCartonId
          : selectedInventories[0].cartonId
        : null

      const response = await client.mutate({
        mutation: gql`
          mutation undoReplenishmentPutaway($worksheetDetailName: [String]!, $cartonId: String) {
            undoReplenishmentPutaway(worksheetDetailName: $worksheetDetailName, cartonId: $cartonId)
          }
        `,
        variables: {
          worksheetDetailName: selectedInventories.map(inventory => inventory.name),
          cartonId: cartonId
        }
      })

      if (!response.errors) {
        return response
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  _focusOnLotInput() {
    setTimeout(() => this.lotInput.focus(), 100)
  }

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

  _validateScanInventory() {
    if (this.enableCartonLabel) {
      if (!this.cartonInput?.value) {
        this._focusOnCartonInput()
        throw new Error(i18next.t('text.carton_id_is_empty'))
      }
    } else {
      if (!this.lotInput?.value) {
        this._focusOnLotInput()
        throw new Error(i18next.t('text.lot_id_is_empty'))
      }
    }
  }

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

window.customElements.define('undo-putaway-popup', UndoPutawayPopup)
