import { MultiColumnFormStyles } from '@things-factory/form-ui'
import '@things-factory/grist-ui'
import { getRenderer } from '@things-factory/grist-ui'
import { i18next, localize } from '@things-factory/i18n-base'
import { openPopup } from '@things-factory/layout-base'
import { client, CustomAlert, navigate, PageView } from '@things-factory/shell'
import { CommonButtonStyles } from '@things-factory/styles'
import { isMobileDevice } from '@things-factory/utils'
import gql from 'graphql-tag'
import { css, html } from 'lit-element'
import '../../components/attachment-viewer'
import '../../components/popup-note'
import '../../components/vas-templates'
import {
  ORDER_STATUS,
  VAS_BATCH_AND_PRODUCT_TYPE,
  VAS_BATCH_NO_TYPE,
  VAS_ETC_TYPE,
  VAS_PRODUCT_TYPE
} from '../../constants'

//vas --inbound
class ReceiveArrivalNotice extends localize(i18next)(PageView) {
  static get properties() {
    return {
      _ganNo: String,
      _ownTransport: Boolean,
      _crossDocking: Boolean,
      _importCargo: Boolean,
      _hasContainer: Boolean,
      _looseItem: Boolean,
      _bizplaceName: String,
      _attachments: Array,
      productGristConfig: Object,
      vasGristConfig: Object,
      productData: Object,
      vasData: Object,
      _template: Object
    }
  }

  static get styles() {
    return [
      MultiColumnFormStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow-x: auto;
        }
        .container {
          flex: 1;
          display: flex;
        }
        .grist {
          background-color: var(--main-section-background-color);
          display: flex;
          flex-direction: column;
          flex: 1;
          overflow-y: auto;
        }
        .guide-container {
          max-width: 30vw;
          display: flex;
          flex-direction: column;
        }
        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 {
          margin: var(--grist-title-margin);
          border: var(--grist-title-border);
          font: var(--grist-title-font);
          color: var(--secondary-color);
        }

        .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);
        }

        h2 + data-grist {
          padding-top: var(--grist-title-with-grid-padding);
        }
        [options-wrap] *,
        [attachment-wrap] a * {
          vertical-align: middle;
        }
        [options-wrap] input[type='checkbox'] {
          left: 0;
        }
        [options-wrap] input[type='checkbox'] + label {
          margin-right: 20px;
          padding-left: 0;
        }
        [attachment-wrap] {
          grid-column: span 9 / auto;
        }
        [attachment-wrap] a {
          display: block;
          text-overflow: ellipsis;
          overflow: hidden;
          white-space: nowrap;
          color: var(--primary-color);
          font-size: var(--fontsize-default);
        }
        [attachment-wrap] {
          margin: 0;
          padding: 0;
          list-style: none;
        }
        [attachment-wrap] a mwc-icon {
          font-size: var(--fontsize-default);
        }
      `
    ]
  }

  get context() {
    return {
      title: i18next.t('title.receive_arrival_notice'),
      actions: [
        {
          title: i18next.t('button.back'),
          action: () => history.back(),
          ...CommonButtonStyles.back
        },
        {
          title: i18next.t('button.reject'),
          action: this._rejectArrivalNotice.bind(this),
          ...CommonButtonStyles.reject
        },
        {
          title: i18next.t('button.receive'),
          action: this._receiveArrivalNotice.bind(this),
          ...CommonButtonStyles.receive
        }
      ],
      help: 'operato-wms/arrival-notice/receive-arrival-notice'
    }
  }

  render() {
    return html`
      <form name="arrivalNotice" class="multi-column-form">
        <fieldset>
          <legend>${i18next.t('title.gan_no')}: ${this._ganNo}</legend>

          <label>${i18next.t('label.options')}</label>
          <div options-wrap>
            <input
              id="ownTransport"
              type="checkbox"
              name="ownTransport"
              ?checked="${this._ownTransport}"
              @change="${e => (this._ownTransport = e.currentTarget.checked)}"
              disabled
            />
            <label>${i18next.t('label.own_transport')}</label>

            <input
              id="warehouseTransport"
              type="checkbox"
              name="warehouseTransport"
              ?checked="${!this._ownTransport}"
              disabled
            />
            <label>${i18next.t('label.warehouse_transport')}</label>

            <input id="container" type="checkbox" name="container" ?checked="${this._hasContainer}" disabled />
            <label for="container">${i18next.t('label.container')}</label>

            <input id="looseItem" type="checkbox" name="looseItem" ?checked="${this._looseItem}" disabled />
            <label for="looseItem">${i18next.t('label.loose_item')}</label>

            <input id="importCargo" type="checkbox" name="importCargo" ?checked="${this._importCargo}" disabled />
            <label>${i18next.t('label.import_cargo')}</label>

            ${this._crossDocking
              ? html`
                  <input
                    id="crossDocking"
                    type="checkbox"
                    name="crossDocking"
                    ?checked="${this._crossDocking}"
                    disabled
                  />
                  <label for="crossDocking">${i18next.t('label.cross_docking')}</label>
                `
              : ''}
          </div>

          <label>${i18next.t('label.company')}</label>
          <input name="bizplaceName" value="${this._bizplaceName}" readonly />

          <label>${i18next.t('label.ref_no')}${`1`}</label>
          <input name="refNo" readonly />

          <label>${i18next.t('label.ref_no')}${`2`}</label>
          <input name="refNo2" readonly />

          <label>${i18next.t('label.ref_no')}${`3`}</label>
          <input name="refNo3" readonly />

          <label>${i18next.t('label.eta_date')}</label>
          <input name="etaDate" type="date" readonly />

          <label ?hidden="${!this._ownTransport}">${i18next.t('label.do_no')}</label>
          <input name="deliveryOrderNo" ?hidden="${!this._ownTransport}" readonly />

          <label ?hidden="${this._importCargo || !this._ownTransport}">${i18next.t('label.truck_no')}</label>
          <input ?hidden="${this._importCargo || !this._ownTransport}" name="truckNo" readonly />

          <label ?hidden="${!this._hasContainer}">${i18next.t('label.container_no')}</label>
          <input ?hidden="${!this._hasContainer}" type="text" name="containerNo" readonly />

          <label>${i18next.t('label.container_size')}</label>
          <input type="text" name="containerSize" readonly />

          <label>${i18next.t('label.status')}</label>
          <select name="status" disabled>
            ${Object.keys(ORDER_STATUS).map(key => {
              const status = ORDER_STATUS[key]
              return html` <option value="${status.value}">${i18next.t(`label.${status.name}`)}</option> `
            })}
          </select>

          ${this._attachments?.length > 0
            ? html`
                <label>${i18next.t('label.attachment')}</label>
                <ul attachment-wrap>
                  ${(this._attachments || []).map(
                    attachment =>
                      html`
                        <li>
                          <a href="${location.origin}/attachment/${attachment.path}" download
                            ><mwc-icon>attach_file</mwc-icon> ${attachment.name}</a
                          >
                        </li>
                      `
                  )}
                </ul>
              `
            : ''}
        </fieldset>
      </form>

      <div class="container">
        <div class="grist">
          <h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.product')}</h2>

          <data-grist
            id="product-grist"
            .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
            .config=${this.productGristConfig}
            .data="${this.productData}"
          ></data-grist>

          <h2><mwc-icon>list_alt</mwc-icon>${i18next.t('title.vas')}</h2>

          <data-grist
            id="vas-grist"
            .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
            .config=${this.vasGristConfig}
            .data="${this.vasData}"
          ></data-grist>
        </div>

        <div class="guide-container">${this._template}</div>
      </div>
    `
  }

  constructor() {
    super()
    this.productData = { records: [] }
    this._downloadable = true
    this._attachments = []
    this.vasData = { records: [] }
  }

  get arrivalNoticeForm() {
    return this.shadowRoot.querySelector('form[name=arrivalNotice]')
  }

  get _ownTransportInput() {
    return this.shadowRoot.querySelector('input[name=ownTransport]')
  }

  get productGrist() {
    return this.shadowRoot.querySelector('data-grist#product-grist')
  }

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

  pageInitialized() {
    this.vasGristConfig = {
      list: { fields: ['set', 'targetType', 'target', 'packingType', 'qty', 'vas', 'status', 'remark'] },
      pagination: { infinite: true },
      rows: {
        appendable: false,
        handlers: {
          click: (columns, data, column, record, rowIndex) => {
            if (record && record.vas && record.vas.operationGuideType === 'template') {
              this._template = document.createElement(record.vas.operationGuide)
              this._template.record = { ...record, operationGuide: JSON.parse(record.operationGuide) }
            } else {
              this._template = null
            }
          }
        }
      },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'string',
          name: 'set',
          header: i18next.t('field.set'),
          width: 60
        },
        {
          type: 'string',
          name: 'targetType',
          header: i18next.t('field.target_type'),
          width: 200
        },
        {
          type: 'string',
          name: 'target',
          header: i18next.t('field.target'),
          record: {
            renderer: (value, column, record, rowIndex, field) => {
              if (record.targetType === VAS_BATCH_NO_TYPE) {
                return getRenderer()(record.targetBatchId, column, record, rowIndex, field)
              } else if (record.targetType === VAS_PRODUCT_TYPE) {
                return getRenderer('object')(record.targetProduct, column, record, rowIndex, field)
              } else if (record.targetType === VAS_BATCH_AND_PRODUCT_TYPE) {
                return getRenderer()(
                  `${record.targetBatchId} / ${record.targetProduct.name}`,
                  column,
                  record,
                  rowIndex,
                  field
                )
              } else if (record.targetType === VAS_ETC_TYPE) {
                return getRenderer()(record.otherTarget, column, record, rowIndex, field)
              }
            }
          },

          width: 250
        },
        {
          type: 'string',
          name: 'packingType',
          header: i18next.t('field.packing_type'),
          width: 120
        },
        {
          type: 'integer',
          name: 'qty',
          header: i18next.t('field.qty'),
          width: 60
        },
        {
          type: 'integer',
          name: 'uomValue',
          header: i18next.t('field.uom_value'),
          width: 60
        },
        {
          type: 'object',
          name: 'vas',
          header: i18next.t('field.vas'),
          record: { options: { queryName: 'vass' } },
          width: 150
        },
        {
          type: 'string',
          name: 'status',
          header: i18next.t('field.status'),
          width: 150
        },
        {
          type: 'string',
          name: 'remark',
          header: i18next.t('field.remark'),
          width: 250
        }
      ]
    }
  }

  pageUpdated(changes) {
    if (this.active && changes.resourceId) {
      this._ganNo = changes.resourceId
      this._fetchGAN()
    }
  }

  async _fetchGAN() {
    if (!this._ganNo) return
    this._status = ''
    const response = await client.query({
      query: gql`
        query arrivalNotice($name: String!) {
          arrivalNotice(name: $name) {
            name
            bizplace {
              id
              name
            }
            containerNo
            containerSize
            ownTransport
            crossDocking
            releaseGood {
              id
            }
            etaDate
            looseItem
            deliveryOrderNo
            status
            truckNo
            refNo
            refNo2
            refNo3
            importCargo
            attachment {
              id
              name
              refBy
              path
              mimetype
            }
            orderProducts {
              id
              batchId
              batchIdRef
              adjustedBatchId
              adjustedBatchIdRef
              product {
                id
                name
                description
                sku
                brand
              }
              remark
              unitPrice
              adjustedUnitPrice
              status
              packingType
              adjustedPackingType
              packingSize
              uomValue
              adjustedUomValue
              uom
              adjustedUom
              packQty
              adjustedPackQty
              totalUomValue
              adjustedTotalUomValue
              palletQty
              adjustedPalletQty
              manufactureYear
              releaseQty
              releaseUomValue
            }
            orderVass {
              vas {
                name
                operationGuide
                operationGuideType
              }
              set
              targetType
              targetBatchId
              targetProduct {
                id
                name
                description
              }
              packingType
              qty
              uomValue
              otherTarget
              description
              remark
              status
              operationGuide
            }
          }
        }
      `,
      variables: { name: this._ganNo }
    })

    if (!response.errors) {
      const { arrivalNotice } = response.data
      const { orderProducts, orderVass } = arrivalNotice

      this.orderBizplace = arrivalNotice.bizplace
      this._hasContainer = arrivalNotice.containerNo ? true : false
      this._looseItem = arrivalNotice.looseItem
      this._ownTransport = arrivalNotice.ownTransport
      this._crossDocking = arrivalNotice.crossDocking
      this._importCargo = arrivalNotice.importCargo
      this._status = arrivalNotice.status
      this._bizplaceName = arrivalNotice.bizplace.name

      this._fillupANForm({ ...arrivalNotice })

      if (arrivalNotice && arrivalNotice?.attachment) {
        this._attachments = arrivalNotice && arrivalNotice.attachment
      }

      this.setProductGristConfig()
      this.productData = {
        records: orderProducts.map(record => {
          return { ...record, productSku: record.product.sku, productBrand: record.product.brand }
        })
      }
      this.vasData = {
        records: orderVass
          .sort((a, b) => a.set - b.set)
          .map(orderVas => {
            return {
              ...orderVas,
              set: `Set ${orderVas.set}`
            }
          })
      }
    }
  }

  setProductGristConfig() {
    const crossDockingColumns = [
      {
        type: 'integer',
        name: 'releaseQty',
        header: i18next.t('field.release_qty'),
        record: { editable: true },
        width: 160
      },
      {
        type: 'float',
        name: 'releaseUomValue',
        header: i18next.t('field.release_uom_value'),
        record: { editable: true },
        width: 160
      }
    ]

    let productGristColumns = [
      { type: 'gutter', gutterName: 'sequence' },
      {
        type: 'string',
        name: 'batchId',
        header: i18next.t('field.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: 'productBrand',
        header: i18next.t('field.brand'),
        width: 150
      },
      {
        type: 'string',
        name: 'packingType',
        header: i18next.t('field.packing_type'),
        width: 150
      },
      {
        type: 'float',
        name: 'uomValue',
        header: i18next.t('field.uom_value'),
        width: 100
      },
      {
        type: 'string',
        name: 'uom',
        header: i18next.t('field.uom'),
        width: 80
      },
      {
        type: 'float',
        name: 'packQty',
        header: i18next.t('field.pack_qty'),
        width: 80
      },
      {
        type: 'integer',
        name: 'totalUomValue',
        header: i18next.t('field.total_uom_value'),
        width: 120
      },
      {
        type: 'integer',
        name: 'palletQty',
        header: i18next.t('field.pallet_qty'),
        width: 80
      },
      {
        type: 'number',
        name: 'manufactureYear',
        header: i18next.t('field.manufacture_year'),
        width: 100
      },
      {
        type: 'string',
        name: 'batchIdRef',
        header: i18next.t('field.batch_no_ref'),
        width: 150
      },
      {
        type: 'float',
        name: 'unitPrice',
        header: i18next.t('field.unit_price'),
        width: 80
      },
      {
        type: 'string',
        name: 'remark',
        header: i18next.t('field.remark'),
        width: 300
      }
    ]

    if (this._crossDocking) {
      const packQtyColumnIdx =
        productGristColumns.findIndex(column => column.name === 'packQty') || productGristColumns.length - 1
      productGristColumns.splice(packQtyColumnIdx + 1, 0, ...crossDockingColumns)
    }

    this.productGristConfig = {
      list: { fields: ['batchId', 'product', 'packingType', 'totalUomValue'] },
      pagination: { infinite: true },
      rows: { selectable: { multiple: true }, appendable: false },
      columns: productGristColumns
    }
  }

  _fillupANForm(data) {
    this._fillupForm(this.arrivalNoticeForm, data)
  }

  _fillupForm(form, data) {
    for (let key in data) {
      Array.from(form.querySelectorAll('input, textarea, select')).forEach(field => {
        if (field.name === key && field.type === 'checkbox') {
          field.checked = data[key]
        } else if (field.name === key && field.type !== 'file') {
          field.value = data[key]
        }
      })
    }
  }

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

      if (!result.value) return

      if (this._crossDocking) {
        result = await CustomAlert({
          title: i18next.t('title.are_you_sure'),
          text: i18next.t('text.this_is_cross_docking'),
          confirmButton: { text: i18next.t('button.confirm') },
          cancelButton: { text: i18next.t('button.cancel') }
        })

        if (!result.value) return
      }

      const response = await client.mutate({
        mutation: gql`
          mutation receiveArrivalNotice($name: String!) {
            receiveArrivalNotice(name: $name) {
              name
            }
          }
        `,
        variables: { name: this._ganNo }
      })

      if (!response.errors) {
        navigate(`arrival_notice_requests`)
        this._showToast({ message: i18next.t('text.arrival_notice_received') })
      }
    } catch (e) {
      this._showToast(e)
    }
  }

  async _rejectArrivalNotice() {
    const popup = openPopup(
      html`
        <popup-note
          .title="${i18next.t('title.remark')}"
          @submit="${async e => {
            try {
              if (!e.detail.value) throw new Error(i18next.t('text.remark_is_empty'))
              const result = await CustomAlert({
                title: i18next.t('title.are_you_sure'),
                text: i18next.t('text.reject_arrival_notice'),
                confirmButton: { text: i18next.t('button.confirm') },
                cancelButton: { text: i18next.t('button.cancel') }
              })

              if (!result.value) return

              if (this._crossDocking) {
                const result = await CustomAlert({
                  title: i18next.t('title.cross_docking'),
                  text: i18next.t('text.related_release_order_will_be_rejected'),
                  confirmButton: { text: i18next.t('button.confirm') },
                  cancelButton: { text: i18next.t('button.cancel') }
                })

                if (!result.value) return
              }

              const response = await client.mutate({
                mutation: gql`
                  mutation rejectArrivalNotice($name: String!, $patch: ArrivalNoticePatch!) {
                    rejectArrivalNotice(name: $name, patch: $patch) {
                      name
                    }
                  }
                `,
                variables: { name: this._ganNo, patch: { remark: e.detail.value } }
              })

              if (!response.errors) {
                navigate('arrival_notice_requests')
                this._showToast({ message: i18next.t('text.arrival_notice_rejected') })
              }
            } catch (e) {
              this._showToast(e)
            }
          }}"
        ></popup-note>
      `,
      {
        backdrop: true,
        size: 'medium',
        title: i18next.t('title.reject_arrival_notice')
      }
    )
  }

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

window.customElements.define('receive-arrival-notice', ReceiveArrivalNotice)
