import '@things-factory/grist-ui'
import '@things-factory/import-ui'
import '../../../components/vas-templates'
import './vas-create-batch-product-type-form'
import './vas-create-batch-type-form'
import './vas-create-etc-type-form'
import './vas-create-product-type-form'

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

import { MultiColumnFormStyles } from '@things-factory/form-ui'
import { i18next, localize } from '@things-factory/i18n-base'
import { isMobileDevice } from '@things-factory/utils'

import {
  VAS_BATCH_AND_PRODUCT_TYPE,
  VAS_BATCH_NO_TYPE,
  VAS_ETC_TYPE,
  VAS_PRODUCT_TYPE,
  VAS_SPECIAL_TYPE,
  VAS_TARGET_TYPES
} from '../../../constants'

//vas --inbound. Inbound still use this popup.
export class VasCreatePopup extends localize(i18next)(LitElement) {
  static get styles() {
    return [
      MultiColumnFormStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow: hidden;
          background-color: white;
        }
        .grist {
          display: flex;
          flex-direction: column;
          flex: 1;
          overflow-y: auto;
        }
        .grist-container {
          overflow-y: hidden;
          display: flex;
          flex: 1;
        }
        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);
        }
        .button-container button {
          background-color: var(--button-container-button-background-color);
          border-radius: var(--button-container-button-border-radius);
          height: var(--button-container-button-height);
          border: var(--button-container-button-border);
          margin: var(--button-container-button-margin);

          padding: var(--button-padding);
          color: var(--theme-white-color);
          font: var(--button-font);
          text-transform: var(--button-text-transform);
        }
        .button-container button:hover,
        .button-container button:active {
          background-color: var(--button-background-focus-color);
        }
        .vas-container {
          display: flex;
          flex-direction: row;
          flex: 1;
          overflow-y: auto;
          padding-bottom: 10px;
        }
        .vas-column {
          flex: 1;
          display: flex;
          flex-direction: column;
          overflow: auto;
        }
      `
    ]
  }

  static get properties() {
    return {
      _template: Object,
      bizplaceId: Object,
      record: Object,
      selectedPackingType: String,
      selectedTargetType: String,
      targetGristConfig: Object,
      targetData: Object,
      targetList: Array,
      vasGristConfig: Object,
      vasGristData: Object,
      vasList: Array
    }
  }

  get targetGrist() {
    return this.shadowRoot.querySelector('#target-grist')
  }

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

  get targetTypeForm() {
    return this.shadowRoot.querySelector('form#target-type')
  }

  get batchTypeInput() {
    return this.shadowRoot.querySelector('input#batchId')
  }

  get productTypeInput() {
    return this.shadowRoot.querySelector('input#product')
  }

  get etcTypeInput() {
    return this.shadowRoot.querySelector('input#etc')
  }

  get targetForm() {
    return this.shadowRoot.querySelector('.vas-create-form')
  }

  get targetInfo() {
    if (this.selectedTargetType === VAS_BATCH_AND_PRODUCT_TYPE || this.selectedTargetType === VAS_SPECIAL_TYPE) {
      if (this.targetGrist?.selected && this.targetGrist.selected.some(record => record.assignedUomValue > 0)) {
        return this.targetGrist.selected
          .filter(
            record =>
              (record.assignedPackQty && record.assignedPackQty <= record.packQty) ||
              (record.assignedUomValue && record.assignedUomValue <= record.totalUomValue)
          )
          .map(record => {
            return {
              targetType: this.selectedTargetType,
              targetDisplay: `${record.batchId} - ${record.product.name} ${
                record.product.description ? '(' + record.product.description + ')' : ''
              }`,
              target: { batchId: record.batchId, productId: record.product.id },
              packingType: record.packingType,
              packingSize: record.packingSize,
              qty: record.assignedPackQty,
              uomValue: (record.totalUomValue / record.packQty) * record.assignedPackQty
            }
          })
      }
    } else {
      if (this.targetForm && this.targetForm.checkValidity()) {
        return [
          {
            targetType: this.selectedTargetType,
            targetDisplay: this.targetForm.targetDisplay,
            target: this.targetForm.target,
            packingType: this.targetForm.selectedPackingType,
            qty: (this.targetForm.qty && parseInt(this.targetForm.qty)) || '',
            uomValue: (this.targetForm.uomValue && parseFloat(this.targetForm.uomValue)) || ''
          }
        ]
      }
    }
  }

  render() {
    return html`
      <form id="target-type" class="multi-column-form" @change="${this._onTypeFormchangeHandler}">
        <label>${i18next.t('label.target_type')}</label>
        <select id="target-types-selector">
          ${VAS_TARGET_TYPES.map(
            type =>
              html`<option value="${type.value}" ?selected="${this.record && this.record.targetType === type.value}">
                ${type.display}
              </option>`
          )}
        </select>
      </form>

      ${this.selectedTargetType === VAS_BATCH_NO_TYPE
        ? html`
            <vas-create-batch-type-form
              class="vas-create-form"
              .targetList="${this.targetList}"
              .vasList="${this.vasList}"
              .record="${this.record}"
              @form-change="${this.resetVasTemplates}"
            ></vas-create-batch-type-form>
          `
        : this.selectedTargetType === VAS_PRODUCT_TYPE
        ? html`
            <vas-create-product-type-form
              class="vas-create-form"
              .targetList="${this.targetList}"
              .vasList="${this.vasList}"
              .record="${this.record}"
              @form-change="${this.resetVasTemplates}"
            ></vas-create-product-type-form>
          `
        : this.selectedTargetType === VAS_BATCH_AND_PRODUCT_TYPE || this.selectedTargetType === VAS_SPECIAL_TYPE
        ? html`
            <div class="vas-grist-container">
              <div class="grist">
                <h2>${i18next.t('title.target_product')}</h2>
                <data-grist
                  id="target-grist"
                  .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
                  .config=${this.targetGristConfig}
                  .data="${this.targetData}"
                  @field-change="${this._calculateData.bind(this)}"
                  @select-record-change="${this._setOperationGuideFilter.bind(this)}"
                ></data-grist>
              </div>
            </div>
          `
        : this.selectedTargetType === VAS_ETC_TYPE
        ? html`
            <vas-create-etc-type-form
              class="vas-create-form"
              .record="${this.record}"
              @form-change="${this.resetVasTemplates}"
            ></vas-create-etc-type-form>
          `
        : ''}
      ${this.selectedTargetType
        ? html`
            <div class="vas-container">
              <div class="vas-column">
                <div class="grist">
                  <h2>${i18next.t('title.vas')}</h2>
                  <data-grist
                    id="vas-grist"
                    .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
                    .config=${this.vasGristConfig}
                    .data="${this.vasGristData}"
                    @field-change="${this._onFieldChange.bind(this)}"
                  ></data-grist>
                </div>
              </div>

              ${this._template ? html`<div class="vas-column">${this._template}</div>` : ''}
            </div>
          `
        : ''}

      <div class="button-container">
        ${this._template
          ? html`
              <mwc-button
                raised
                danger
                @click="${async e => {
                  const copied = Object.assign(this.vasGrist.dirtyData, {})
                  try {
                    this.vasGristData = {
                      ...this.vasGrist.dirtyData,
                      records: await Promise.all(
                        this.vasGrist.dirtyData.records.map(async (record, idx) => {
                          if (idx === this._selectedVasRecordIdx) {
                            record.operationGuide = await this._template.adjust()
                            record.ready = this._isReadyToCreate(record)
                          }
                          return record
                        })
                      )
                    }
                  } catch (e) {
                    this._showToast(e)
                    this.vasGristData = Object.assign(copied)
                  }
                }}"
              >
                ${i18next.t('button.adjust')}
              </mwc-button>
            `
          : ''}
        <mwc-button
          raised
          danger
          @click=${() => {
            history.back()
          }}
        >
          ${i18next.t('button.cancel')}
        </mwc-button>
        <mwc-button raised danger @click="${this.confirmHandler.bind(this)}">${i18next.t('button.confirm')}</mwc-button>
      </div>
    `
  }

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

  updated(changedProps) {
    if (changedProps.has('selectedTargetType')) {
      this._template = null
      this.vasGristData = { ...this.vasGristData, records: [] }
      this._updateTargetGristConfig()
      this.setVasQueryFilter()
    }
  }

  firstUpdated() {
    this.targetData = { records: [...this.targetList] }
    this.targetGristConfig = {
      list: {
        fields: ['batchId', 'product', 'packingType', 'packQty', 'assignedPackQty', 'totalUomValue', 'assignedUomValue']
      },
      pagination: { infinite: true },
      rows: { appendable: false, selectable: { multiple: true } },
      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: 'object',
          name: 'product',
          header: i18next.t('field.product'),
          width: 350
        },
        {
          type: 'string',
          name: 'packingType',
          header: i18next.t('field.packing_type'),
          width: 150
        },
        {
          type: 'float',
          name: 'packingSize',
          header: i18next.t('field.packing_size'),
          width: 150
        },
        {
          type: 'string',
          name: 'uom',
          header: i18next.t('field.uom'),
          width: 80
        },
        {
          type: 'integer',
          name: 'packQty',
          header: i18next.t('field.pack_qty'),
          width: 80
        },
        {
          type: 'integer',
          name: 'assignedPackQty',
          header: i18next.t('field.assigned_pack_qty'),
          record: { editable: true, options: { min: 0 } },
          width: 80
        },
        {
          type: 'float',
          name: 'totalUomValue',
          header: i18next.t('field.total_uom_value'),
          width: 120
        },
        {
          type: 'float',
          name: 'assignedUomValue',
          header: i18next.t('field.assigned_uom_value'),
          record: { editable: true, options: { min: 0.0 } },
          width: 120
        }
      ]
    }

    this.vasGristConfig = {
      list: { fields: ['ready', 'vas', 'batchId', 'remark'] },
      pagination: { infinite: true },
      rows: {
        selectable: { multiple: true },
        handlers: {
          click: (columns, data, column, record, rowIndex) => {
            if (!this.targetInfo || !this.targetInfo?.length) {
              this._showToast({
                message: i18next.t('text.vas_target_does_not_specified')
              })

              return
            }

            if (
              this.targetGrist &&
              this.targetGrist.selected &&
              this.targetGrist.selected.length !==
                this.targetGrist.dirtyData.records.filter(record => record.assignedUomValue > 0).length
            ) {
              this._showToast({
                message: i18next.t('text.please_check_your_vas_target')
              })

              return
            }

            if (record && record.vas && record.vas.operationGuideType === 'template' && record.vas.operationGuide) {
              this._template = document.createElement(record.vas.operationGuide)
              this._template.record = record
              this._template.targetInfo = this.targetInfo
              this._template.bizplaceId = this.bizplaceId
            } else {
              this._template = null
            }
            this._selectedVasRecord = record
            this._selectedVasRecordIdx = rowIndex
          }
        }
      },
      columns: [
        {
          type: 'gutter',
          gutterName: 'button',
          icon: 'close',
          handlers: {
            click: (columns, data, column, record, rowIndex) => {
              this.vasGristData = { ...this.vasGristData, records: data.records.filter((_, idx) => idx !== rowIndex) }
              this.setVasQueryFilter()
            }
          }
        },
        {
          type: 'boolean',
          name: 'ready',
          header: i18next.t('field.ready'),
          width: 40
        },
        {
          type: 'object',
          name: 'vas',
          header: i18next.t('field.vas'),
          record: {
            editable: true,
            align: 'center',
            options: {
              queryName: 'vass',
              select: [
                { name: 'id', hidden: true },
                { name: 'name', width: 160 },
                { name: 'description', width: 200 },
                { name: 'operationGuide', hidden: true },
                { name: 'operationGuideType', hidden: true }
              ],
              list: { fields: ['name', 'description'] }
            }
          },
          width: 250
        },
        {
          type: 'string',
          name: 'remark',
          header: i18next.t('field.remark'),
          record: { editable: true },
          width: 400
        }
      ]
    }

    if (this.record && this.record.orderVass && this.record.orderVass.length) {
      this.selectedTargetType = this.record.targetType
      this.vasGristData = { records: this.record.orderVass }
    }
  }

  _onTypeFormchangeHandler(e) {
    this.selectedTargetType = e.target.value

    this.vasGristData = { records: [] }
    this._setOperationGuideFilter()
  }

  _updateTargetGristConfig() {
    const config = this.targetGristConfig
    const rows = config.rows
    const columns = config.columns.filter(column => column.type != 'gutter' && column.name != 'row-selector')
    this.targetData = {
      ...this.targetData,
      records: [...this.targetList]
    }

    if (this.selectedTargetType == VAS_BATCH_AND_PRODUCT_TYPE) {
      this.targetGristConfig = {
        ...config,
        rows: {
          ...rows,
          selectable: {
            multiple: true
          }
        },
        columns: [{ type: 'gutter', gutterName: 'row-selector', multiple: true }, ...columns]
      }
    } else if (this.selectedTargetType == VAS_SPECIAL_TYPE) {
      this.targetGristConfig = {
        ...config,
        rows: {
          ...rows,
          selectable: {
            multiple: false
          }
        },
        columns: [{ type: 'gutter', gutterName: 'row-selector', multiple: false }, ...columns]
      }
    }
  }

  _onFieldChange(e) {
    if (e.detail.column.name === 'vas') {
      this._template = null
      delete this.vasGrist.dirtyData.records[e.detail.row].operationGuide
    }

    this.vasGristData = {
      ...this.vasGrist.dirtyData,
      records: this.vasGrist.dirtyData.records.map(record => {
        return {
          ...record,
          ready: this._isReadyToCreate(record)
        }
      })
    }

    this.setVasQueryFilter()
  }

  _setOperationGuideFilter() {
    if (this.selectedTargetType === VAS_SPECIAL_TYPE) {
      const columns = this.vasGristConfig.columns.map(column => {
        if (
          column.name &&
          column.name === 'vas' &&
          column.record &&
          column.record.options &&
          column.record.options.basicArgs
        ) {
          column.record.options.basicArgs.filters = column.record.options.basicArgs.filters.filter(
            x => x.name !== 'operationGuideType'
          )
        }
        return column
      })

      this.vasGristConfig = {
        ...this.vasGristConfig,
        columns
      }
    }
  }

  _calculateData(e) {
    const { after, column, record, row } = e.detail

    let assignedPackQty, assignedUomValue

    if (column.name == 'assignedPackQty') {
      if (!after || after > record.packQty) {
        this._showToast({
          message: i18next.t('text.invalid_value_in_list')
        })
      } else {
        assignedPackQty = after
        assignedUomValue = Math.round((record.totalUomValue / record.packQty) * assignedPackQty * 100) / 100
      }
    } else if (column.name == 'assignedUomValue') {
      if (!after || after > record.totalUomValue) {
        this._showToast({
          message: i18next.t('text.invalid_value_in_list')
        })
      } else {
        assignedUomValue = after
        assignedPackQty = ''
      }
    }

    this.targetData = {
      ...this.targetData,
      records: this.targetData.records.map((targetRecord, idx) => {
        if (idx == row) {
          return { ...record, assignedPackQty, assignedUomValue }
        } else return targetRecord
      })
    }

    this._setOperationGuideFilter()
  }

  _calculateData2() {
    this.targetData = {
      ...this.targetData,
      records: this.targetGrist.dirtyData.records.map(record => {
        let assignedPackQty = 0
        let assignedUomValue = 0

        if (record.assignedPackQty > record.packQty || record.assignedPackQty < 0) {
          this._showToast({
            message: i18next.t('text.assigned_pack_qty_is_invalid')
          })
        } else {
          assignedPackQty = record.assignedPackQty || 0
          assignedUomValue = Math.round((record.totalUomValue / record.packQty) * assignedPackQty * 100) / 100
        }

        if (assignedPackQty && assignedPackQty > 0)
          return {
            ...record,
            assignedPackQty,
            assignedUomValue
          }
        else return record
      })
    }

    this._setOperationGuideFilter()
  }

  _isReadyToCreate(record) {
    if (record.vas && record.vas.operationGuideType) {
      return Boolean(record.operationGuide && record.remark)
    } else if (record.vas && !record.vas.operationGuideType) {
      return Boolean(record.vas && record.remark)
    } else {
      return false
    }
  }

  confirmHandler() {
    try {
      this._checkValidity()
      this.dispatchEvent(
        new CustomEvent('completed', {
          detail: this.targetInfo.map(target => {
            // reset target type to VAS_BATCH_AND_PRODUCT_TYPE
            if (target.targetType === VAS_SPECIAL_TYPE) target.targetType = VAS_BATCH_AND_PRODUCT_TYPE

            return {
              ...target,
              ready: true,
              vasCount: this.vasGrist.dirtyData.records.length,
              orderVass: this.vasGrist.dirtyData.records
            }
          })
        })
      )
      history.back()
    } catch (e) {
      this._showToast(e)
    }
  }

  _checkValidity() {
    if (this.selectedTargetType !== VAS_BATCH_AND_PRODUCT_TYPE && this.selectedTargetType !== VAS_SPECIAL_TYPE) {
      // Target form validity checking
      if (!this.targetForm.checkValidity()) throw new Error(i18next.t('text.invalid_form'))
    }

    // Vas grist validity checking
    if (this.vasGrist.dirtyData.records.length == 0) throw new Error(i18next.t('text.there_is_no_vas'))
    if (this.vasGrist.dirtyData.records.some(record => !record.ready))
      throw new Error(i18next.t('text.invalid_vas_setting'))
  }

  resetVasTemplates() {
    this._template = null

    this.vasGrist.data = {
      ...this.vasGrist.data,
      records: this.vasGrist.data.records.map(record => {
        if (record && record.operationGuide) {
          delete record.operationGuide
          record.ready = false
        }

        return record
      })
    }
  }

  async setVasQueryFilter() {
    if (!this.selectedTargetType) return
    await this.updateComplete

    let vasIds = []
    if (this.vasGristData && this.vasGristData.records && this.vasGristData.records.length) {
      vasIds = this.vasGristData.records.filter(record => record.vas && record.vas.id).map(record => record.vas.id)
    }

    const selectedVasFilter = { name: 'id', operator: 'notin', value: vasIds }
    const specialVasFilter = {
      name: 'operationGuide',
      value: ['vas-repack', 'vas-repalletizing', 'vas-relabel', 'vas-unpack', 'vas-repack-relabel']
    }

    const columns = this.vasGristConfig.columns.map(column => {
      if (column.name && column.name === 'vas' && column.record && column.record.options) {
        if (vasIds.length) {
          column.record.options.basicArgs =
            this.selectedTargetType === VAS_SPECIAL_TYPE
              ? { filters: [{ ...specialVasFilter, operator: 'in' }, selectedVasFilter] }
              : { filters: [{ ...specialVasFilter, operator: 'notin_with_null' }, selectedVasFilter] }
        } else {
          column.record.options.basicArgs =
            this.selectedTargetType === VAS_SPECIAL_TYPE
              ? { filters: [{ ...specialVasFilter, operator: 'in' }] }
              : { filters: [{ ...specialVasFilter, operator: 'notin_with_null' }] }
        }
      }
      return column
    })

    this.vasGristConfig = {
      ...this.vasGristConfig,
      columns
    }
  }

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

window.customElements.define('vas-create-popup', VasCreatePopup)
