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, sleep } from '@things-factory/utils'

import { fetchSettingRule } from '../../fetch-setting-value'

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

  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: 'productId', hidden: true },
        { type: 'string', name: 'productDetailId', hidden: true },
        {
          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: 'etaDate',
          header: i18next.t('field.eta_date'),
          width: 150
        },
        {
          type: 'string',
          name: 'truckNo',
          header: i18next.t('field.truck_no'),
          width: 150
        },
        {
          type: 'string',
          name: 'containerNo',
          header: i18next.t('field.container_no'),
          width: 150
        },
        {
          type: 'string',
          name: 'containerSize',
          header: i18next.t('field.container_size'),
          width: 150
        },
        {
          type: 'boolean',
          name: 'looseItem',
          header: i18next.t('field.loose_item'),
          width: 150
        },
        {
          type: 'boolean',
          name: 'importCargo',
          header: i18next.t('field.import_cargo'),
          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: 'batchIdRef',
          header: i18next.t('field.batch_no_ref'),
          width: 150
        },
        {
          type: 'string',
          name: 'palletId',
          header: i18next.t('field.lot_id'),
          width: 100
        },
        {
          type: 'float',
          name: 'packQty',
          header: i18next.t('field.pack_qty'),
          width: 150
        },
        {
          type: 'float',
          name: 'uomValue',
          header: i18next.t('field.uom_value'),
          width: 150
        },
        {
          type: 'string',
          name: 'totalUomValue',
          header: i18next.t('field.total_uom_value'),
          width: 150
        },
        {
          type: 'string',
          name: 'uom',
          header: i18next.t('field.uom'),
          width: 100
        },
        {
          type: 'integer',
          name: 'palletQty',
          header: i18next.t('field.pallet_qty'),
          width: 100
        },
        {
          type: 'float',
          name: 'unitPrice',
          header: i18next.t('field.unit_price'),
          width: 100
        },
        {
          type: 'string',
          name: 'manufactureDate',
          header: i18next.t('field.manufacture_date'),
          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._ganConfig}></data-grist>
      </div>

      <div class="button-container">
        <mwc-button
          @click=${async () => {
            const answer = await CustomAlert({
              title: i18next.t('label.create_arrival_notices'),
              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._generateArrivalNotices(this.records, this.bizplaceId)
          }}
          >${i18next.t('button.create_gan')}</mwc-button
        >
        <mwc-button @click=${e => history.back()}>${i18next.t('button.cancel')}</mwc-button>
      </div>
    `
  }

  constructor() {
    super()
    this._enableLotIdInput = false
    this._isValidating = true
  }

  async firstUpdated() {
    this._ganConfig = this._config
    await this.updateComplete
    await this.dataGrist.updateComplete
    this.dataGrist.showSpinner()
    this._enableLotIdInput = await fetchSettingRule('enable-lot-id-input')
    await this._getValidatedArrivalNoticeItems(this.records, this.bizplaceId)
  }

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

  async _getValidatedArrivalNoticeItems(rawArrivalNotices, bizplaceId) {
    try {
      rawArrivalNotices.map(raw => {
        if (raw.unitPrice) {
          raw.unitPrice = parseFloat(raw.unitPrice)
        }
      })
      const response = await client.query({
        query: gql`
          query validateBulkArrivalNotices($rawArrivalNotices: [NewArrivalNotice!], $bizplaceId: String!) {
            validateBulkArrivalNotices(rawArrivalNotices: $rawArrivalNotices, bizplaceId: $bizplaceId) {
              refNo
              refNo2
              refNo3
              etaDate
              truckNo
              ownTransport
              containerNo
              containerSize
              container
              looseItem
              importCargo
              productId
              productDetailId
              sku
              productInfo
              batchId
              batchIdRef
              packingType
              packingSize
              uom
              packQty
              uomValue
              totalUomValue
              palletQty
              palletId
              unitPrice
              manufactureDate
              errorMsg
            }
          }
        `,
        variables: { rawArrivalNotices, bizplaceId }
      })
      if (!response.errors) {
        this._isValidating = false
        this.records = response.data.validateBulkArrivalNotices
        this.records.map(record => {
          if (record.unitPrice) {
            record.unitPrice = record.unitPrice.toFixed(2)
          }
        })
      }
    } catch (e) {
      console.error(e)
    } finally {
      this.dataGrist.hideSpinner()
    }
  }

  async _generateArrivalNotices(rawArrivalNotices, bizplaceId) {
    this.dataGrist.showSpinner()

    try {
      this._validateArrivalNotices()

      if (rawArrivalNotices) {
        rawArrivalNotices = rawArrivalNotices.map(raw => {
          return {
            refNo: raw.refNo,
            refNo2: raw.refNo2,
            refNo3: raw.refNo3,
            etaDate: raw.etaDate,
            truckNo: raw.truckNo,
            ownTransport: !!raw.truckNo || false,
            looseItem: !!raw.looseItem || false,
            importCargo: !!raw.importCargo || false,
            container: (!!raw.containerNo && !!raw.containerSize) || false,
            containerNo: raw.containerNo,
            containerSize: raw.containerSize,
            sku: raw.sku,
            batchId: raw.batchId ? raw.batchId.trim() : raw.batchId,
            batchIdRef: raw.batchIdRef ? raw.batchIdRef.trim() : raw.batchIdRef,
            packingType: raw.packingType,
            packingSize: raw.packingSize,
            uom: raw.uom,
            packQty: raw.packQty,
            palletQty: raw.palletQty,
            palletId: raw.palletId,
            unitPrice: parseFloat(raw.unitPrice),
            manufactureDate: raw.manufactureDate
          }
        })
      }

      const response = await client.mutate({
        mutation: gql`
          mutation bulkGenerateArrivalNotices($rawArrivalNotices: [NewArrivalNotice!], $bizplaceId: String!) {
            bulkGenerateArrivalNotices(rawArrivalNotices: $rawArrivalNotices, bizplaceId: $bizplaceId) {
              items {
                name
              }
            }
          }
        `,
        variables: {
          rawArrivalNotices,
          bizplaceId
        }
      })

      if (!response.errors) {
        this._showToast({ message: i18next.t('text.arrival_notices_created') })

        if (this.ganProcessing == '1') {
          let arrivalNoticeNos = response.data.bulkGenerateArrivalNotices.items.map(itm => itm.name)
          this.dispatchEvent(new CustomEvent('gan-processing-setting', { detail: arrivalNoticeNos }))
        }
      } else {
        let invalidDataError = response.errors.find(err => err.extensions.exception.errorCode == 'ivd1')
        if (invalidDataError) {
          this.records = JSON.parse(invalidDataError.extensions.exception.detail.data)
          this._showToast({ message: i18next.t('text.please_recheck_your_request_data') })
        }
      }
    } catch (e) {
      this._showToast(e)
    } finally {
      history.back()
      this.dataGrist.hideSpinner()
      await sleep(1)
    }
  }

  _validateArrivalNotices() {
    if (this.records.some(record => record.errorMsg && record.errorMsg != '')) {
      throw new Error(i18next.t('text.please_recheck_your_request_data'))
    }
    if (this._enableLotIdInput == false) {
      //make sure no batchId and sku pair is duplicated in the same gan
      let batchSkuPairs = this.records
        .filter(item => item.batchId !== null && item.sku !== null) // Filter out items with null batchId or sku
        .map(item => `${item.batchId.toLowerCase()}-${item.sku.toLowerCase()}-${item.refNo.toLowerCase()}`) // Create a combined key of batchId and sku

      let uniqueBatchSkuPairs = new Set(batchSkuPairs)
      if (uniqueBatchSkuPairs.size !== batchSkuPairs.length) {
        throw new Error(i18next.t('text.duplicated_batch_id_and_sku'))
      }
    } else {
      let palletIds = this.records.map(item => item.palletId).filter(palletId => palletId !== null)

      let uniquePalletIds = new Set(palletIds)
      if (uniquePalletIds.size !== palletIds.length) {
        throw new Error(i18next.t('text.duplicated_lot_id'))
      }
    }
  }

  _getStdDateStr(date) {
    if (isNaN(date.getFullYear())) return ''
    else {
      date.setHours(date.getHours() + 8)
      return date.toISOString().split('T')[0]
    }
  }

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

window.customElements.define('validate-gan-popup', ValidateGanPopup)
