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'

import { ORDER_PRODUCT_STATUS } from '../../constants'

export class ProceedEditProductPopup extends localize(i18next)(LitElement) {
  static get styles() {
    return [
      ScrollbarStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow: hidden;
          background-color: white;
        }
        .grist-container {
          overflow-y: auto;
          display: flex;
          flex: 1;
          margin: 10px;
        }
        .grist {
          display: flex;
          flex-direction: column;
          flex: 1;
          overflow-y: auto;
        }
        .grist 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);
        }
        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);
        }
        .grist h2 {
          font: var(--grist-title-font);
        }
        .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);
        }
        mwc-button[danger] {
          --mdc-theme-primary: var(--status-danger-color, #d14946) !important;
        }
      `
    ]
  }

  static get properties() {
    return {
      config: Object,
      data: Object,
      bizplace: Object,
      ganNo: String,
      enableDirectInbound: Boolean
    }
  }

  render() {
    return html`
      <div class="grist-container">
        <div class="grist">
          <h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.approve')}</h2>
          <data-grist
            id="approve-grist"
            .mode="${isMobileDevice() ? 'LIST' : 'GRID'}"
            .config="${this.config}"
            .data="${this.approvedData}"
          ></data-grist>
        </div>

        <div class="grist">
          <h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.reject')}</h2>
          <data-grist
            id="reject-grist"
            .mode="${isMobileDevice() ? 'LIST' : 'GRID'}"
            .config="${this.config}"
            .data="${this.rejectedData}"
          ></data-grist>
        </div>
      </div>

      <div class="button-container">
        <mwc-button
          raised
          @click="${this._approveProducts.bind(this)}"
          label="${i18next.t('button.approve')}"
        ></mwc-button>
        <mwc-button
          raised
          danger
          @click="${this._rejectProducts.bind(this)}"
          label="${i18next.t('button.reject')}"
        ></mwc-button>
        <mwc-button
          raised
          ?danger="${this._isAllProductsRemoved}"
          @click="${this._proceedExtraProducts.bind(this)}"
          label="${this._isAllProductsRemoved ? i18next.t('button.cancel_order') : i18next.t('button.confirm')}"
        ></mwc-button>
      </div>
    `
  }

  constructor() {
    super()
    this.approvedData = { records: [] }
    this.rejectedData = { records: [] }
  }

  get approveGrist() {
    return this.shadowRoot.querySelector('data-grist#approve-grist')
  }

  get rejectGrist() {
    return this.shadowRoot.querySelector('data-grist#reject-grist')
  }

  get _isAllProductsRemoved() {
    if (!this.approveGrist || !this.rejectGrist || !this.data || !this.data.records) return false

    const totalProductCount = this.data.records.length
    if (totalProductCount === 0) return false

    let removeCount = 0

    const approvedRecords = this.approveGrist.data.records || []
    approvedRecords.forEach(record => {
      const packQty =
        record.adjustedPackQty !== undefined && record.adjustedPackQty !== null
          ? record.adjustedPackQty
          : record.packQty
      const palletQty =
        record.adjustedPalletQty !== undefined && record.adjustedPalletQty !== null
          ? record.adjustedPalletQty
          : record.palletQty

      if (!packQty && !palletQty) {
        removeCount++
      }
    })

    const rejectedRecords = this.rejectGrist.data.records || []
    rejectedRecords.forEach(record => {
      if (record.status === ORDER_PRODUCT_STATUS.ADDED.value) {
        removeCount++
      }
    })

    return removeCount === totalProductCount
  }

  updated(changedProps) {
    if (changedProps.has('data')) {
      this.approvedData = {
        ...this.data,
        records: this.data.records.filter(
          item => item.status === ORDER_PRODUCT_STATUS.ADDED.value || item.status === ORDER_PRODUCT_STATUS.EDITED.value
        )
      }
    }
  }

  firstUpdated() {
    const columns = [
      { type: 'gutter', gutterName: 'sequence' },
      { type: 'gutter', gutterName: 'row-selector', multiple: true },
      {
        type: 'string',
        name: 'batchId',
        header: i18next.t('field.batch_id'),
        width: 150
      },
      {
        type: 'string',
        name: 'adjustedBatchId',
        header: i18next.t('field.adjusted_batch_id'),
        width: 150
      },
      {
        type: 'string',
        name: 'productSku',
        header: i18next.t('field.sku'),
        width: 150
      },
      {
        type: 'object',
        name: 'product',
        header: i18next.t('field.product'),
        record: { options: { queryName: 'products' } },
        width: 350
      },
      {
        type: 'string',
        name: 'packingType',
        header: i18next.t('field.packing_type'),
        width: 150
      },
      {
        type: 'string',
        name: 'adjustedPackingType',
        header: i18next.t('field.adjusted_packing_type'),
        width: 150
      },
      {
        type: 'float',
        name: 'uomValue',
        header: i18next.t('field.uom_value'),
        width: 80
      },
      {
        type: 'float',
        name: 'adjustedUomValue',
        header: i18next.t('field.adjusted_uom_value'),
        width: 80
      },
      {
        type: 'string',
        name: 'uom',
        header: i18next.t('field.uom'),
        width: 80
      },
      {
        type: 'string',
        name: 'adjustedUom',
        header: i18next.t('field.adjusted_uom'),
        width: 80
      },
      {
        type: 'float',
        name: 'packQty',
        header: i18next.t('field.pack_qty'),
        width: 80
      },
      {
        type: 'float',
        name: 'adjustedPackQty',
        header: i18next.t('field.adjusted_pack_qty'),
        width: 80
      },
      {
        type: 'float',
        name: 'totalUomValue',
        header: i18next.t('field.total_uom_value'),
        width: 120
      },
      {
        type: 'integer',
        name: 'adjustedTotalUomValue',
        header: i18next.t('field.adjusted_total_uom_value'),
        width: 120
      },
      {
        type: 'integer',
        name: 'palletQty',
        header: i18next.t('field.pallet_qty'),
        width: 80
      },
      {
        type: 'integer',
        name: 'adjustedPalletQty',
        header: i18next.t('field.adjusted_pallet_qty'),
        width: 80
      },
      {
        type: 'date',
        name: 'manufactureDate',
        header: i18next.t('field.manufacture_date'),
        width: 120
      },
      {
        type: 'string',
        name: 'batchIdRef',
        header: i18next.t('field.batch_no_ref'),
        width: 150
      },
      {
        type: 'string',
        name: 'adjustedBatchIdRef',
        header: i18next.t('field.adjusted_batch_id_ref'),
        width: 150
      },
      {
        type: 'float',
        name: 'unitPrice',
        header: i18next.t('field.unit_price'),
        width: 80
      },
      {
        type: 'float',
        name: 'adjustedUnitPrice',
        header: i18next.t('field.adjusted_unit_price'),
        width: 80
      },
      {
        type: 'string',
        name: 'remark',
        header: i18next.t('field.remark'),
        width: 200
      }
    ]

    function insertAfter(cols, anchorName, newCols) {
      const idx = cols.findIndex(c => c.name === anchorName)
      if (idx >= 0) cols.splice(idx + 1, 0, ...newCols)
    }

    const expDateColumn = {
      type: 'date',
      name: 'expDate',
      header: i18next.t('field.exp_date'),
      width: 120
    }

    const adjustedExpDateColumn = {
      type: 'date',
      name: 'adjustedExpDate',
      header: i18next.t('field.adjusted_exp_date'),
      width: 120
    }

    const locationColumn = {
      type: 'object',
      name: 'location',
      header: i18next.t('field.location'),
      width: 150
    }

    const adjustedLocationColumn = {
      type: 'object',
      name: 'adjustedLocation',
      header: i18next.t('field.adjusted_location'),
      width: 150
    }

    const warehouseColumn = {
      type: 'object',
      name: 'warehouse',
      header: i18next.t('field.warehouse'),
      width: 150
    }

    const adjustedWarehouseColumn = {
      type: 'object',
      name: 'adjustedWarehouse',
      header: i18next.t('field.adjusted_warehouse'),
      width: 150
    }

    if (this.enableDirectInbound) {
      insertAfter(columns, 'adjustedPalletQty', [expDateColumn, adjustedExpDateColumn])
      insertAfter(columns, 'adjustedBatchIdRef', [warehouseColumn, locationColumn, adjustedWarehouseColumn, adjustedLocationColumn])
    }

    this.config = this.productGristConfig = {
      list: {
        fields: [
          'batchId',
          'adjustedBatchId',
          'productSku',
          'product',
          'packingType',
          'adjustedPackingType',
          'packQty',
          'adjustedPackQty',
          'palletQty',
          'adjustedPalletQty',
          'uom',
          'adjustedUom',
          'totalUomValue',
          'adjustedTotalUomValue',
          'batchIdRef',
          'adjustedBatchIdRef',
          'unitPrice',
          'adjustedUnitPrice'
        ]
      },
      pagination: { infinite: true },
      rows: { selectable: { multiple: true }, appendable: false },
      columns
    }
  }

  async _approveProducts() {
    if (!this.rejectGrist.selected || !this.rejectGrist.selected.length) return
    const approvedData = [...this.approveGrist.data.records, ...this.rejectGrist.selected]
    const rejectedData = this.rejectGrist.dirtyData.records.filter(record => {
      if (!record['__selected__']) {
        delete record['__selected__']
        return record
      } else {
        delete record['__selected__']
      }
    })

    this.approveGrist.data = { records: [] }
    this.rejectGrist.data = { records: [] }

    await this.approveGrist.updateComplete
    await this.rejectGrist.updateComplete

    this.approveGrist.data = { records: approvedData }
    this.rejectGrist.data = { records: rejectedData }
  }

  async _rejectProducts() {
    if (!this.approveGrist.selected || !this.approveGrist.selected.length) return
    const rejectedData = [...this.rejectGrist.data.records, ...this.approveGrist.selected]
    const approvedData = this.approveGrist.dirtyData.records.filter(record => {
      if (!record['__selected__']) {
        delete record['__selected__']
        return record
      } else {
        delete record['__selected__']
      }
    })

    this.approveGrist.data = { records: [] }
    this.rejectGrist.data = { records: [] }

    await this.approveGrist.updateComplete
    await this.rejectGrist.updateComplete

    this.approveGrist.data = { records: approvedData }
    this.rejectGrist.data = { records: rejectedData }
  }

  async _proceedExtraProducts() {
    try {
      const result = await CustomAlert({
        title: i18next.t('title.are_you_sure'),
        type: this._isAllProductsRemoved ? 'warning' : 'question',
        text: this._isAllProductsRemoved
          ? i18next.t('text.approving_change_will_cancel_order_irreversible')
          : i18next.t('text.you_wont_be_able_to_revert_this'),
        confirmButton: {
          text: this._isAllProductsRemoved ? i18next.t('button.cancel_order') : i18next.t('button.confirm'),
          color: this._isAllProductsRemoved ? '#d14946' : '#22a6a7'
        },
        cancelButton: { text: i18next.t('button.cancel') }
      })

      if (!result.value) return

      const response = await client.mutate({
        mutation: gql`
          mutation proceedExtraProducts(
            $ganNo: String!
            $bizplaceId: String!
            $approvedProducts: [ProductApproval]!
            $rejectedProducts: [ProductApproval]!
          ) {
            proceedExtraProducts(
              ganNo: $ganNo
              bizplaceId: $bizplaceId
              approvedProducts: $approvedProducts
              rejectedProducts: $rejectedProducts
            )
          }
        `,
        variables: {
          ganNo: this.ganNo,
          bizplaceId: this.bizplace.id,
          approvedProducts: this.approveGrist.data.records.map(record => {
            return { id: record.id, status: record.status }
          }),
          rejectedProducts: this.rejectGrist.data.records.map(record => {
            return { id: record.id, status: record.status }
          })
        }
      })

      if (!response.errors) {
        this._showToast({ message: i18next.t('text.product_changes_have_been_processed') })
        this.dispatchEvent(new CustomEvent('completed'))
        window.history.back()
      }
    } catch (e) {
      this._showToast(e)
    }
  }

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

window.customElements.define('proceed-edit-product-popup', ProceedEditProductPopup)
