import '@things-factory/barcode-ui'
import '../../inbound/select-location-popup'

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

import { sleep } from '@operato/utils'
import { MultiColumnFormStyles } from '@things-factory/form-ui'
import { i18next, localize } from '@things-factory/i18n-base'
import { openPopup } from '@things-factory/layout-base'
import { client, CustomAlert } from '@things-factory/shell'
import { isMobileDevice } from '@things-factory/utils'

class PopupReverseKittingTemplate extends localize(i18next)(LitElement) {
  static get properties() {
    return {
      reverseKittingOIName: String,
      data: Object,
      productSku: String,
      qty: Number,
      actualQty: Number,
      incompleteLocationName: Boolean,
      locations: Array,
      _selectedInventory: Object,
      reverseKittingInventoriesConfig: Object,
      _reverseKittingInventories: Array,
      _palletId: String,
      _locationCode: String
    }
  }

  static get styles() {
    return [
      MultiColumnFormStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow-x: overlay;
          background-color: var(--main-section-background-color);
        }
        .container {
          display: flex;
          flex-direction: column;
          flex: 1;
        }
        .container > textarea {
          flex: 1;
          resize: none;
          border-color: var(--primary-color);
          padding: 5px;
          margin: 10px;
          outline: none;
        }
        h2 {
          padding: var(--subtitle-padding);
          font: var(--grist-title-font);
          margin: var(--grist-title-margin);
          border: var(--grist-title-border);
          color: var(--secondary-color);
        }
        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);
        }
        .button-container {
          padding: 10px 0 12px 0;
          text-align: center;
        }
      `
    ]
  }

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

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

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

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

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

  render() {
    return html`
      <form class="multi-column-form" id="input-form" @keypress="${this._executeReverseKitting.bind(this)}">
        <fieldset>
          <legend>${this.productSku} [ ${this.actualQty} / ${this.qty} ]</legend>

          <label>${i18next.t('label.lot_id')}</label>
          <barcode-scanable-input
            name="palletId"
            value="${this._palletId}"
            without-enter
            custom-input
          ></barcode-scanable-input>

          <label>${i18next.t('label.qty')}</label>
          <input name="qty" type="number" value="" min="1" />

          <label>${i18next.t('label.location')}</label>
          <barcode-scanable-input
            name="locationCode"
            value="${this._locationCode}"
            without-enter
            custom-input
          ></barcode-scanable-input>
        </fieldset>
      </form>

      ${this._reverseKittingInventories?.records?.length
        ? html`<h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.inventories')}</h2>
            <div class="grist">
              <data-grist
                id="combination-grist"
                .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
                .config=${this.reverseKittingInventoriesConfig}
                .data=${this._reverseKittingInventories}
              ></data-grist>
            </div>
            <div class="button-container">
              <mwc-button
                raised
                @click=${this._confirmInventory.bind(this)}
                label="${i18next.t('button.confirm')}"
              ></mwc-button>
              <mwc-button
                raised
                @click=${this._undoInventory.bind(this)}
                label="${i18next.t('button.undo')}"
              ></mwc-button>
            </div> `
        : html`<div class="button-container">
            <mwc-button
              raised
              @click=${this._confirmInventory.bind(this)}
              label="${i18next.t('button.confirm')}"
            ></mwc-button>
          </div> `}
    `
  }

  async firstUpdated() {
    this._palletId = ''
    this._locationCode = ''
    this.productSku = this.data.productSku
    this.qty = this.data.qty
    this.actualQty = this.data.actualQty

    this.reverseKittingInventoriesConfig = {
      rows: {
        appendable: false,
        handlers: {
          click: (columns, data, column, record, rowIndex) => {
            this._selectedInventory = record
            this._palletId = record.palletId
            this._locationCode = record.locationCode
            this._fillUpForm(this.inputForm, record)
          }
        }
      },
      list: {
        fields: ['sku', 'product', 'batchId', 'palletId', 'packingType', 'packingSize', 'qty']
      },
      pagination: { infinite: true },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'string',
          name: 'sku',
          header: i18next.t('field.sku'),
          label: true,
          width: 120
        },
        {
          type: 'object',
          name: 'product',
          header: i18next.t('field.product'),
          label: true,
          width: 240
        },
        {
          type: 'string',
          name: 'batchId',
          header: i18next.t('field.batch_id'),
          label: true,
          width: 120
        },
        {
          type: 'string',
          name: 'palletId',
          header: i18next.t('field.lot_id'),
          label: true,
          width: 120
        },
        {
          type: 'string',
          name: 'packingType',
          header: i18next.t('field.packing_type'),
          label: true,
          width: 120
        },
        {
          type: 'string',
          name: 'packingSize',
          header: i18next.t('field.packing_size'),
          label: true,
          width: 120
        },
        {
          type: 'integer',
          name: 'qty',
          header: i18next.t('field.actual_pack_qty'),
          label: true,
          width: 80
        }
      ]
    }

    await this._fetchInventories()
    this._focusOnPalletInput()
  }

  async _fetchInventories() {
    const response = await client.query({
      query: gql`
        query reverseKittingInventories($reverseKittingOIName: String!, $productDetailId: String!) {
          reverseKittingInventories(reverseKittingOIName: $reverseKittingOIName, productDetailId: $productDetailId) {
            batchId
            packingType
            bizplace {
              id
              name
              description
            }
            packingSize
            batchIdRef
            palletId
            cartonId
            qty
            expirationDate
            status
            location {
              id
              name
              description
            }
            product {
              id
              name
              sku
              isRequiredCheckExpiry
            }
          }
        }
      `,
      variables: { reverseKittingOIName: this.reverseKittingOIName, productDetailId: this.data.productDetailId }
    })

    if (!response.errors) {
      this._reverseKittingInventories = {
        records:
          response.data.reverseKittingInventories.map(reverseKittingInventory => {
            return {
              ...reverseKittingInventory,
              sku: reverseKittingInventory.product.sku,
              packingTypeSize: `${reverseKittingInventory.packingType}(${reverseKittingInventory.packingSize})`,
              locationCode: reverseKittingInventory.location.name
            }
          }) || []
      }

      let totalActualQty = 0
      response.data.reverseKittingInventories.forEach(inventory => {
        totalActualQty += inventory.qty
      })

      this.actualQty = totalActualQty
    }
  }

  async _executeReverseKitting(e) {
    if (e.keyCode === 13) {
      e.preventDefault()
      try {
        await this._validateReverseKitting()
        if (!this.incompleteLocationName) {
          const response = await client.mutate({
            mutation: gql`
              mutation executeReverseKitting($name: String!, $inventory: InventoryPatch!) {
                executeReverseKitting(name: $name, inventory: $inventory)
              }
            `,
            variables: {
              name: this.reverseKittingOIName,
              inventory: {
                palletId: this.palletInput.value.trim(),
                qty: parseInt(this.qtyInput.value),
                locationName: this.locationInput.value.trim(),
                productDetailId: this.data.productDetailId
              }
            }
          })
          if (!response.errors) {
            this._clearView()
            await this._fetchInventories()
          }
        } else {
          this._openSelectLocationPopup()
        }
      } catch (e) {
        this._showToast(e)
      }
    }
  }

  async _undoInventory() {
    try {
      this._validateSelectedInventory()
      const result = await CustomAlert({
        title: i18next.t('title.are_you_sure'),
        text: i18next.t('text.undo_x', { state: { x: this._palletId } }),
        confirmButton: { text: i18next.t('button.confirm') },
        cancelButton: { text: i18next.t('button.cancel') }
      })

      if (!result.value) {
        return
      }

      let response = await client.mutate({
        mutation: gql`
          mutation undoReverseKittingInventory($reverseKittingOIName: String!, $palletId: String!) {
            undoReverseKittingInventory(reverseKittingOIName: $reverseKittingOIName, palletId: $palletId)
          }
        `,
        variables: {
          reverseKittingOIName: this.reverseKittingOIName,
          palletId: this._palletId.trim()
        }
      })

      if (!response.errors) {
        this._clearView()
        await this._fetchInventories()
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  _confirmInventory() {
    this.dispatchEvent(new CustomEvent('updated', { detail: {} }))
    history.back()
  }

  _fillUpForm(form, data) {
    for (let key in data) {
      Array.from(form.querySelectorAll('input')).forEach(field => {
        if (field.name === key && field.type === 'checkbox') {
          field.checked = data[key]
        } else if (field.name === key && field.type === 'datetime-local') {
          const datetime = Number(data[key])
          const timezoneOffset = new Date(datetime).getTimezoneOffset() * 60000
          field.value = new Date(datetime - timezoneOffset).toISOString().slice(0, -1)
        } else if (field.name === key) {
          if (data[key] instanceof Object) {
            const objectData = data[key]
            field.value = `${objectData.name} ${objectData.description ? `(${objectData.description})` : ''}`
          } else {
            field.value = data[key]
          }
        }
      })
    }
  }

  _clearView() {
    this.inputForm.reset()
    this._palletId = ''
    this._locationCode = ''
  }

  async _validateReverseKitting() {
    if (!this.palletInput.value) {
      this._focusOnPalletInput()
      throw new Error(i18next.t('text.lot_id_is_empty'))
    }

    if (!this.qtyInput.value) {
      this._focusOnQtyInput()
      throw new Error(i18next.t('text.qty_is_empty'))
    } else {
      if (!this.qtyInput.checkValidity()) throw new Error(i18next.t('text.invalid_qty'))
    }

    // 4. location code existing
    if (!this.locationInput.value) {
      this._focusOnLocationInput()
      throw new Error(i18next.t('text.location_code_is_empty'))
    } else if (this.locationInput.value) {
      const foundLocation = await this._fetchLocation(this.locationInput.value.trim())
      if (!foundLocation) {
        const locationNameSplit = this.locationInput.value.split('-')
        const zonePortions = locationNameSplit[0].match(/[a-zA-Z0-9]+/g)
        const rowPortions = locationNameSplit[1].match(/[a-zA-Z0-9]+/g)
        const columnPortions = locationNameSplit[2].match(/[a-zA-Z0-9]+/g)

        if (locationNameSplit.length === 3) {
          this.incompleteLocationName = true
          this.locations = await this._fetchLocations(zonePortions[0], rowPortions[0], columnPortions[0])
        }
      } else {
        this.incompleteLocationName = false
      }
    }
  }

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

  async _fetchLocations(zone, row, column) {
    const filters = [
      {
        name: 'zone',
        operator: 'eq',
        value: zone
      },
      {
        name: 'row',
        operator: 'eq',
        value: row
      },
      {
        name: 'column',
        operator: 'eq',
        value: column
      }
    ]

    if (filters) {
      const response = await client.query({
        query: gql`
          query locations($filters: [Filter!]) {
            locations(filters: $filters) {
              items {
                id
                name
                zone
                row
                column
                shelf
                status
              }
            }
          }
        `,
        variables: { filters }
      })

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

  async _fetchLocation(locationName) {
    if (locationName) {
      const response = await client.query({
        query: gql`
          query location($name: String!) {
            location(name: $name) {
              id
              name
              zone
              row
              column
              shelf
            }
          }
        `,
        variables: { name: locationName }
      })

      if (!response.errors) {
        return response.data.location
      }
    }
  }

  async _openSelectLocationPopup() {
    await sleep(1010)
    openPopup(
      html`
        <select-location-popup
          .locations="${this.locations}"
          @location-selected="${e => {
            this.locationInput.value = e.detail.location.name
            this.incompleteLocationName = false
            this._executeReverseKitting(e.detail)
          }}"
        ></select-location-popup>
      `,
      {
        backdrop: true,
        size: 'medium',
        title: i18next.t('title.select_location')
      }
    )
  }

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

  _focusOnQtyInput() {
    setTimeout(() => this.qtyInput.focus(), 100)
  }

  _focusOnLocationInput() {
    setTimeout(() => this.locationInput.focus(), 100)
  }

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

window.customElements.define('popup-reverse-kitting-template', PopupReverseKittingTemplate)
