import '@material/mwc-button/mwc-button'
import '@things-factory/grist-ui'

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

import { i18next, localize } from '@things-factory/i18n-base'
import { client, CustomAlert } from '@things-factory/shell'
import { ScrollbarStyles } from '@things-factory/styles'
import { isMobileDevice } from '@things-factory/utils'

class ValidateRoPopup extends localize(i18next)(LitElement) {
  static get properties() {
    return {
      _roConfig: Object,
      bizplaceId: String,
      records: Array
    }
  }

  static get styles() {
    return [
      ScrollbarStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow: hidden;
          background-color: white;

          --grid-record-emphasized-background-color: #ffdbdb;
          --grid-record-emphasized-color: #703f3f;
        }

        .grist {
          display: flex;
          flex-direction: column;
          flex: 1;
          overflow-y: auto;
        }
        data-grist {
          overflow-y: hidden;
          flex: 1;
        }
        h2 {
          padding: var(--subtitle-padding);
          font: var(--subtitle-font);
          color: var(--subtitle-text-color);
          border-bottom: var(--subtitle-border-bottom);
        }
        .button-container {
          display: flex;
          margin-left: auto;
        }
        .button-container > mwc-button {
          padding: 10px;
        }
      `
    ]
  }

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

  get _config() {
    return {
      list: {},
      pagination: { infinite: true },
      rows: {
        appendable: false,
        classifier: (record, rowIndex) => {
          return {
            emphasized: record.errorMsg && record.errorMsg != ''
          }
        }
      },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'gutter',
          gutterName: 'button',
          icon: 'close',
          handlers: {
            click: (columns, data, column, record, rowIndex) => {
              data.records.splice(rowIndex, 1)
              this.records = data.records
            }
          }
        },
        {
          type: 'string',
          name: 'refNo',
          header: i18next.t('field.ref_no'),
          width: 150
        },
        {
          type: 'string',
          name: 'refNo2',
          header: i18next.t('field.ref_no_2'),
          width: 150
        },
        {
          type: 'string',
          name: 'refNo3',
          header: i18next.t('field.ref_no_3'),
          width: 150
        },
        {
          type: 'string',
          name: 'releaseDate',
          header: i18next.t('field.release_date'),
          width: 150
        },
        {
          type: 'string',
          name: 'attentionTo',
          header: i18next.t('field.attention_to'),
          width: 150
        },
        {
          type: 'string',
          name: 'attentionCompany',
          header: i18next.t('field.attention_company'),
          width: 150
        },
        {
          type: 'string',
          name: 'phone1',
          header: i18next.t('field.phone'),
          width: 150
        },
        {
          type: 'string',
          name: 'deliveryAddress1',
          header: i18next.t('field.delivery_address_1'),
          width: 150
        },
        {
          type: 'string',
          name: 'deliveryAddress2',
          header: i18next.t('field.delivery_address_2'),
          width: 150
        },
        {
          type: 'string',
          name: 'deliveryAddress3',
          header: i18next.t('field.delivery_address_3'),
          width: 150
        },
        {
          type: 'string',
          name: 'deliveryAddress4',
          header: i18next.t('field.delivery_address_4'),
          width: 150
        },
        {
          type: 'string',
          name: 'deliveryAddress5',
          header: i18next.t('field.delivery_address_5'),
          width: 150
        },
        {
          type: 'string',
          name: 'billingAddress',
          header: i18next.t('field.billing_address_1'),
          width: 150
        },
        {
          type: 'string',
          name: 'billingAddress2',
          header: i18next.t('field.billing_address_2'),
          width: 150
        },
        {
          type: 'string',
          name: 'billingAddress3',
          header: i18next.t('field.billing_address_3'),
          width: 150
        },
        {
          type: 'string',
          name: 'billingAddress4',
          header: i18next.t('field.billing_address_4'),
          width: 150
        },
        {
          type: 'string',
          name: 'billingAddress5',
          header: i18next.t('field.billing_address_5'),
          width: 150
        },
        {
          type: 'string',
          name: 'billingPostalCode',
          header: i18next.t('field.billing_postal_code'),
          width: 150
        },
        {
          type: 'string',
          name: 'billingCountry',
          header: i18next.t('field.billing_country'),
          width: 150
        },
        {
          type: 'string',
          name: 'billingState',
          header: i18next.t('field.billing_state'),
          width: 150
        },
        {
          type: 'string',
          name: 'billingCity',
          header: i18next.t('field.billing_city'),
          width: 150
        },
        {
          type: 'string',
          name: 'city',
          header: i18next.t('field.city'),
          width: 150
        },
        {
          type: 'string',
          name: 'postalCode',
          header: i18next.t('field.postal_code'),
          width: 150
        },
        {
          type: 'string',
          name: 'state',
          header: i18next.t('field.state'),
          width: 150
        },
        {
          type: 'string',
          name: 'country',
          header: i18next.t('field.country'),
          width: 150
        },
        {
          type: 'string',
          name: 'sku',
          header: i18next.t('field.sku'),
          width: 150
        },
        {
          type: 'string',
          name: 'productInfo',
          header: i18next.t('field.product_info'),
          width: 400
        },
        {
          type: 'string',
          name: 'batchId',
          header: i18next.t('field.batch_no'),
          width: 150
        },
        {
          type: 'string',
          name: 'cartonId',
          header: i18next.t('field.carton_id'),
          width: 150
        },
        {
          type: 'string',
          name: 'expirationDate',
          header: i18next.t('field.expiry_date'),
          width: 150
        },
        {
          type: 'float',
          name: 'releaseQty',
          header: i18next.t('field.release_qty'),
          width: 150
        },
        {
          type: 'float',
          name: 'assignedQty',
          header: i18next.t('field.assigned_qty'),
          width: 150
        },
        {
          type: 'float',
          name: 'assignedUomValue',
          header: i18next.t('field.assigned_uom_value'),
          width: 150
        },
        {
          type: 'string',
          name: 'uom',
          header: i18next.t('field.uom'),
          width: 100
        },
        {
          type: 'string',
          name: 'packingType',
          header: i18next.t('field.packing_type'),
          width: 100
        },
        {
          type: 'string',
          name: 'packingSize',
          header: i18next.t('field.packing_size'),
          width: 100
        },
        {
          type: 'string',
          name: 'errorMsg',
          header: i18next.t('field.error_message'),
          width: 350
        }
      ]
    }
  }

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

      <div class="button-container">
        <mwc-button
          @click=${async () => {
            const answer = await CustomAlert({
              title: i18next.t('label.create_release_orders'),
              text: i18next.t('text.are_you_sure'),
              confirmButton: { text: i18next.t('button.confirm') },
              cancelButton: { text: i18next.t('button.cancel') }
            })

            if (!answer.value) return
            await this._generateReleaseOrders()
          }}
          >${i18next.t('button.create_ro')}</mwc-button
        >
        <mwc-button @click=${e => history.back()}>${i18next.t('button.cancel')}</mwc-button>
      </div>
    `
  }

  async firstUpdated() {
    this._roConfig = this._config
    await this._getAvailableItems(this.records, this.bizplaceId)
  }

  updated(changedProps) {
    if (changedProps.has('records')) {
      this.dataGrist.data = {
        records: this.records,
        total: this.records.length
      }
    }
  }

  async _getAvailableItems(rawReleaseGoods, bizplaceId) {
    const response = await client.query({
      query: gql`
        query bulkReleaseGoodsAvailableItems($rawReleaseGoods: [NewReleaseGood!], $bizplaceId: String!) {
          bulkReleaseGoodsAvailableItems(rawReleaseGoods: $rawReleaseGoods, bizplaceId: $bizplaceId) {
            refNo
            refNo2
            refNo3
            releaseDate
            deliveryAddress1
            deliveryAddress2
            deliveryAddress3
            deliveryAddress4
            deliveryAddress5
            billingAddress
            billingAddress2
            billingAddress3
            billingAddress4
            billingAddress5
            billingCity
            billingPostalCode
            billingState
            billingCountry
            attentionTo
            attentionCompany
            city
            state
            country
            sku
            productId
            productInfo
            batchId
            expirationDate
            cartonId
            packingType
            packingSize
            uom
            releaseQty
            assignedQty
            assignedUomValue
            postalCode
            phone1
            errorMsg
            exportOption
          }
        }
      `,
      variables: { rawReleaseGoods, bizplaceId }
    })
    this.records = response.data.bulkReleaseGoodsAvailableItems
  }

  async _generateReleaseOrders() {
    this.dataGrist.showSpinner()

    try {
      this._validateReleaseOrders()

      const response = await client.mutate({
        mutation: gql`
          mutation bulkAddReleaseGoods($rawReleaseGoods: [NewReleaseGood!], $bizplaceId: String!) {
            bulkAddReleaseGoods(rawReleaseGoods: $rawReleaseGoods, bizplaceId: $bizplaceId) {
              name
            }
          }
        `,
        variables: {
          rawReleaseGoods: this.records.map(x => {
            // list out all properties again to avoid additional props added by user in excel
            return {
              refNo: x.refNo,
              refNo2: x.refNo2,
              refNo3: x.refNo3,
              releaseDate: x.releaseDate,
              deliveryAddress1: x.deliveryAddress1,
              deliveryAddress2: x.deliveryAddress2,
              deliveryAddress3: x.deliveryAddress3,
              deliveryAddress4: x.deliveryAddress4,
              deliveryAddress5: x.deliveryAddress5,
              billingAddress: x.billingAddress,
              billingAddress2: x.billingAddress2,
              billingAddress3: x.billingAddress3,
              billingAddress4: x.billingAddress4,
              billingAddress5: x.billingAddress5,
              billingCity: x.billingCity,
              billingState: x.billingState,
              billingPostalCode: x.billingPostalCode,
              billingCountry: x.billingCountry,
              attentionTo: x.attentionTo,
              attentionCompany: x.attentionCompany,
              city: x.city,
              state: x.state,
              country: x.country,
              sku: x.sku,
              productId: x.productId,
              packingType: x.packingType,
              packingSize: x.packingSize,
              uom: x.uom,
              releaseQty: x.releaseQty,
              postalCode: String(x.postalCode),
              phone1: String(x.phone1),
              exportOption: false,
              expirationDate: x?.expirationDate ? x.expirationDate : null,
              batchId: x?.batchId ? x.batchId : null,
              cartonId: x?.cartonId ? x.cartonId : null
            }
          }),
          bizplaceId: this.bizplaceId
        }
      })

      if (!response.errors) {
        this._showToast({ message: i18next.t('text.release_order_created') })
        history.back()
      } else {
        let invalidDataError = response.errors.find(err => err.extensions.exception.errorCode == 'ivd1')
        if (invalidDataError) {
          const detail = invalidDataError.extensions.exception.detail
          this.records = JSON.parse(detail.data)

          const successOrders = detail.successOrders || []
          const failedOrders = detail.failedOrders || []

          const parts = []
          if (successOrders.length) {
            parts.push(i18next.t('text.orders_created_successfully') + ': ' + successOrders.join(', '))
          }
          if (failedOrders.length) {
            parts.push(i18next.t('text.orders_have_errors_please_review') + ': ' + failedOrders.join(', '))
          }
          this._showToast({
            type: successOrders.length ? 'warning' : 'error',
            message: parts.join(' | ')
          })
        }
      }
    } catch (e) {
      this._showToast(e)
    } finally {
      this.dataGrist.hideSpinner()
    }
  }

  _validateReleaseOrders() {
    if (this.records.some(record => record.errorMsg && record.errorMsg != '')) {
      throw new Error(i18next.t('text.please_recheck_your_request_data'))
    }
  }

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

window.customElements.define('validate-ro-popup', ValidateRoPopup)
