import '@things-factory/barcode-ui'
import gql from 'graphql-tag'
import { MultiColumnFormStyles } from '@things-factory/form-ui'
import { i18next, localize } from '@things-factory/i18n-base'
import { PageView, store, client, CustomAlert, navigate } from '@things-factory/shell'
import { css, html } from 'lit-element'
import { connect } from 'pwa-helpers/connect-mixin.js'
import { ARRIVAL_NOTICE, RELEASE_OF_GOODS } from '../constants'
import { isMobileDevice } from '@things-factory/utils'
import { CommonButtonStyles } from '@things-factory/styles'
import { showToast } from '../../util/index'
import { openPopup } from '@things-factory/layout-base'
import './add-vas-order-level'
import './execute-pure-vas'
import './execute-ref-vas'

const AVAIL_ORDER_TYPES = { RELEASE_OF_GOODS, ARRIVAL_NOTICE }

//vas
class VasExecution extends connect(store)(localize(i18next)(PageView)) {
  static get properties() {
    return {
      refOrderType: String,
      config: Object,
      data: Object,
      incompleteVas: Boolean,
      orderNo: String,
      _selectedVas: Object,
      bizplaceId: String
    }
  }

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

  render() {
    return html`
      <form class="multi-column-form" id="info-form">
        <fieldset>
          <legend>${i18next.t('title.scan_area')}</legend>
          <label>${i18next.t('label.order_type')}</label>
          <select name="orderType" @change="${this.orderTypeChangeHandler.bind(this)}">
            ${Object.keys(AVAIL_ORDER_TYPES).map(
              key => html`
                <option value="${AVAIL_ORDER_TYPES[key].value}">
                  ${i18next.t(`label.${AVAIL_ORDER_TYPES[key].name}`)}
                </option>
              `
            )}
          </select>

          <label>${i18next.t('label.order_no')}</label>
          <barcode-scanable-input
            name="orderNo"
            custom-input
            @keypress="${this.orderNoKeypressHandler.bind(this)}"
          ></barcode-scanable-input>
        </fieldset>
      </form>

      <!-- Showing proper component based on type of reference order -->
      <div id="form-section">
        <form id="info-form" class="multi-column-form">
          <fieldset>
            <legend>
              ${i18next.t('title.vas')} [
              ${this._selectedVas?.__seq__
                ? this._selectedVas?.__seq__
                : this.data
                ? parseFloat(
                    this.data?.records.map(data => data.targetVas.orderVasItems.executedAt === null).indexOf(true)
                  ) + 1
                : ''}
              ]
            </legend>
          </fieldset>
        </form>
      </div>
      <data-grist id="vas" .mode=${isMobileDevice() ? 'LIST' : 'GRID'} .config=${this.config} .data=${this.data}>
      </data-grist>
    `
  }

  get context() {
    var actions = []

    if (this.incompleteVas !== undefined || null) {
      actions.push({
        title: i18next.t('button.add_vas'),
        action: this.addVas.bind(this),
        ...CommonButtonStyles.additional
      })
    }

    if (this.incompleteVas === true) {
      actions.push({
        title: i18next.t('button.execute'),
        action: this.executeVas.bind(this),
        ...CommonButtonStyles.save
      })
    }

    if (this.incompleteVas === false) {
      actions.push({
        title: i18next.t('button.complete'),
        action: this.completeVas.bind(this),
        ...CommonButtonStyles.submit
      })
    }

    return {
      title: i18next.t('title.vas'),
      help: 'operato-wms/vas/execute-vas',
      actions
    }
  }

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

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

  get childComp() {
    return this.shadowRoot.querySelector('#execute-vas')
  }

  async pageInitialized(changes) {
    this.config = {
      rows: {
        appendable: false,
        handlers: {
          click: async (columns, data, column, record, rowIndex) => {
            this._selectedVas =
              record.executedAt == null
                ? record
                : this.data?.records.map(data => data.targetVas.orderVasItems.executedAt === null)
            this.updateContext()
          }
        }
      },
      pagination: { infinite: true },
      list: {
        fields: ['__seq__', 'done', 'batchId', 'qty', 'vasQty', 'sku', 'newSku', 'outputQty', 'vasRemark', 'vas']
      },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'boolean',
          name: 'done',
          record: { editable: false },
          header: i18next.t('field.done'),
          width: 80
        },
        {
          type: 'string',
          name: 'batchId',
          header: i18next.t('field.batch_id'),
          label: true,
          width: 120
        },
        {
          type: 'string',
          name: 'sku',
          header: i18next.t('field.sku'),
          label: true,
          width: 160
        },
        {
          type: 'string',
          name: 'newSku',
          header: i18next.t('field.new_sku'),
          label: true,
          width: 160
        },
        {
          type: 'number',
          name: 'qty',
          header: i18next.t('field.qty'),
          label: true,
          width: 80
        },
        {
          type: 'number',
          name: 'vasQty',
          header: i18next.t('field.vas_qty'),
          label: true,
          width: 80
        },
        {
          type: 'number',
          name: 'outputQty',
          header: i18next.t('field.output_qty'),
          label: true,
          width: 80
        },
        {
          type: 'string',
          name: 'vasRemark',
          header: i18next.t('field.remark'),
          label: true,
          width: 120
        },
        {
          type: 'object',
          name: 'vas',
          header: i18next.t('field.vas'),
          label: true,
          width: 250
        }
      ]
    }
    if (this.active && changes.params) {
      const { orderNo, orderType } = changes.params
      if (orderNo && orderType) {
        this.refOrderType = orderType
        await this.updateComplete

        this.orderNoInput.value = orderNo
        this.orderTypeSelector.value = orderType

        this.fetchVas()
      }
    }
    await this.updateComplete
    this.orderNoInput.focus()
    this.refOrderType = this.orderTypeSelector.value
  }

  orderTypeChangeHandler(e) {
    this.refOrderType = e.currentTarget.value
    this.orderNoInput.select()
  }

  orderNoKeypressHandler(e) {
    if (e.keyCode === 13) {
      e.preventDefault()

      this.fetchVas()
    }
  }

  async fetchVas() {
    this._selectedVas = this._selectedVas?.__seq__
      ? this._selectedVas.targetVas
      : this.data?.records.find(data => data.targetVas.orderVasItems.executedAt === null)

    const orderNo = this.orderNoInput.value
    this.orderNo = orderNo ? orderNo : this.orderNo
    const orderType = this.refOrderType
    if (!orderNo) return

    const response = await client.query({
      query: gql`
        query vasWorksheet($orderNo: String!, $orderType: String!) {
          vasWorksheet(orderNo: $orderNo, orderType: $orderType) {
            worksheetInfo {
              bizplaceId
              bizplaceName
              startedAt
            }
            worksheetDetailInfos {
              batchId
              targetVas {
                id
                status
                outputQty
                qty
                orderVasItems {
                  id
                  name
                  vasQty
                  vas {
                    id
                    name
                    description
                  }
                  executedAt
                  vasRemark
                }
                product {
                  id
                  sku
                }
                newProduct {
                  id
                  sku
                }
              }
              inventory {
                id
                batchId
                palletId
                qty
                uomValue
              }
              description
              remark
              issue
            }
          }
        }
      `,
      variables: { orderNo, orderType }
    })

    if (!response.errors) {
      const { worksheetInfo, worksheetDetailInfos } = response.data.vasWorksheet
      this.data = { records: this.formatWorksheetDetailInfos(worksheetDetailInfos) }
      this.incompleteVas = this.data.records.find(wd => wd.targetVas?.orderVasItems?.executedAt === null) ? true : false
      this._selectedVas = this._selectedVas?.__seq__
        ? this._selectedVas.targetVas
        : this.data.records.find(data => data.targetVas.orderVasItems.executedAt === null)
      this.updateContext()
      this.bizplaceId = worksheetInfo.bizplaceId
    }
  }

  formatWorksheetDetailInfos(wsdInfos) {
    let wd = []
    wsdInfos
      .filter(wsd => wsd.targetVas.orderVasItems)
      .map(wsd => {
        if (wsd.targetVas.orderVasItems.length > 1) {
          for (let i = 0; i < wsd.targetVas.orderVasItems.length; i++) {
            if (i == 0) {
              wd.push({ ...wsd, targetVas: { ...wsd.targetVas, orderVasItems: wsd.targetVas.orderVasItems[i] } })
            } else {
              wd.push({ targetVas: { id: wsd.targetVas.id, orderVasItems: wsd.targetVas.orderVasItems[i] } })
            }
          }
        } else {
          for (let i = 0; i < wsd.targetVas.orderVasItems.length; i++) {
            wd.push({ ...wsd, targetVas: { ...wsd.targetVas, orderVasItems: wsd.targetVas.orderVasItems[i] } })
          }
        }
      })
    return wd.map(record => {
      return {
        ...record,
        sku: record.targetVas?.product?.sku,
        outputQty: record.targetVas?.outputQty,
        newSku: record.targetVas?.newProduct?.sku,
        qty: record.targetVas?.qty,
        vas: record.targetVas?.orderVasItems?.vas,
        vasQty: record.targetVas?.orderVasItems?.vasQty,
        done: record.targetVas?.orderVasItems?.executedAt !== null ? true : false,
        vasRemark: record.targetVas?.orderVasItems?.vasRemark
      }
    })
  }

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

      if (!result.value) return

      this.validateVas(this._selectedVas?.targetVas?.orderVasItems)
      let patches = this.data.records
        .filter(d => d.targetVas.id == this._selectedVas.targetVas.id)
        .map(d => {
          return { id: d.targetVas.orderVasItems.id, executedAt: new Date().getTime(), cuFlag: 'M' }
        })

      if (patches.length === 0) {
        throw new Error(i18next.t('text.nothing_changed'))
      }

      // if executed one by one not by set
      // patches = [
      //   {
      //     id: patches.id,
      //     executedAt: new Date().getTime(),
      //     cuFlag: 'M'
      //   }
      // ]

      const response = await client.mutate({
        mutation: gql`
          mutation executeOrderVasItems($releaseGoodNo: String!, $patches: [OrderVasItemPatch!]!) {
            executeOrderVasItems(releaseGoodNo: $releaseGoodNo, patches: $patches) {
              id
              name
            }
          }
        `,
        variables: { releaseGoodNo: this.orderNo, patches }
      })

      if (!response.errors) {
        document.dispatchEvent(
          new CustomEvent('notify', {
            detail: {
              message: i18next.t('text.executed')
            }
          })
        )

        this.fetchVas()
        this.updateContext()
      }
    } catch (e) {
      showToast(e)
    }
  }

  validateVas(vas) {
    if (!vas) {
      throw new Error(i18next.t('text.nothing_selected'))
    }
    if (vas.executedAt !== null) {
      throw new Error(i18next.t('text.invalid_input_in_field', { field: i18next.t('text.executed') }))
    }
  }

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

      if (!result.value) return
      const response = await client.mutate({
        mutation: gql`
          mutation completeVas($orderNo: String!, $orderType: String!) {
            completeVas(orderNo: $orderNo, orderType: $orderType)
          }
        `,
        variables: {
          orderNo: this.orderNo,
          orderType: this.refOrderType
        }
      })

      if (!response.errors) {
        this._showToast({ message: i18next.t('text.vas_is_completed') })
        this.clearview()
        this.updateContext()
        navigate('vas_worksheets')
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  addVas() {
    // try {
    //   // const url = `add_vas_order_level?bizplaceId=${this.bizplaceId}&orderNo=${this.orderNo}`
    //   const url = `add_vas_order_level/${this.orderNo}?bizplaceId=${this.bizplaceId}`
    //   navigate(url)
    // } catch (e) {
    //   this.showToast(e)
    // }

    try {
      openPopup(
        html`<add-vas-order-level .bizplaceId="${this.bizplaceId}" .orderNo="${this.orderNo}"></add-vas-order-level>`,
        { backdrop: true, size: 'large', title: i18next.t('title.vas') }
      )
    } catch (e) {
      this.showToast(e)
    }
  }

  get vasGrist() {
    return this.shadowRoot.querySelector('data-grist#vas')
  }

  clearview() {
    this._selectedVas = this._selectedVas?.__seq__
      ? this._selectedVas?.__seq__
      : this.data
      ? parseFloat(this.data?.records.map(data => data.targetVas.orderVasItems.executedAt === null).indexOf(true)) + 1
      : ''
    this.orderNoInput.value = ''
    this.data = { records: [] }
    this.incompleteVas = true
    this.orderNo = ''
  }

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

window.customElements.define('vas-execution', VasExecution)
