import '@things-factory/grist-ui'

import { DirectPrinter } from '@things-factory/barcode-base'
import { MultiColumnFormStyles, SingleColumnFormStyles } from '@things-factory/form-ui'
import { i18next, localize } from '@things-factory/i18n-base'
import { client, store } from '@things-factory/shell'
import { css, html, LitElement } from 'lit-element'
import { connect } from 'pwa-helpers/connect-mixin'
import { sendToPrinter } from '../../util'
import { CARTON_LABEL_BY_SKU_SETTING_KEY, CARTON_LABEL_SETTING_KEY } from '../constants'

import gql from 'graphql-tag'
class CartonLabelPopup extends connect(store)(localize(i18next)(LitElement)) {
  static get properties() {
    return {
      fixedType: String,
      type: String,
      data: Object,
      bizplaceName: String,
      _printer: Object,
      _filters: Array,
      _config: Object,
      enableDirectInbound: Boolean,
      productGristConfig: Object,
      productData: Object,
      arrivalNoticeId: String
    }
  }

  static get styles() {
    return [
      MultiColumnFormStyles,
      SingleColumnFormStyles,
      css`
        :host {
          padding: 10px;
          display: flex;
          flex-direction: column;
          overflow-x: overlay;
          background-color: var(--main-section-background-color);
        }
        .single-column-form {
          width: unset;
          max-width: unset;
        }
        .button-container {
          margin-top: auto;
          text-align: center;
          padding: 10px 0 0 0;
        }
        .container {
          overflow-y: hidden;
          display: flex;
          flex: 1 1 0%;
        }
        .grist {
          display: flex;
          flex-direction: column;
          flex: 1 1 0%;
          overflow-y: auto;
        }
        .form-container {
          display: flex;
        }
        .form-container > form {
          flex: 1;
        }
        h2 + data-grist {
          padding=top: var(--grist-title-with-grid-padding);
        }
        .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);
        }
        .grist h2 {
          margin: var(--grist-title-margin);
          border: var(--grist-title-border);
          font: var(--grist-title-font);
          color: var(--secondary-color);
        }
        h2 {
          padding: var(--subtitle-padding);
          font: var(--subtitle-font);
          color: var(--subtitle-text-color);
          border-bottom: var(--subtitle-border-bottom);
        }
        data-grist {
          overflow-y: hidden;
          flex: 1;
        }
      `
    ]
  }

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

  get printQtyInput() {
    return this.shadowRoot.querySelector('input[name="printQty"]')
  }

  get printType() {
    return this.shadowRoot.querySelector('select[name="printType"]')
  }

  constructor() {
    super()
    this.fixedType = null
    this.type = null
    this.bizplaceName = null
    this.productData = { records: [] }
    this.setProductGristConfig()
  }

  firstUpdated() {
    this.setProductGristConfig()
    this.fetchInventories()
    this._config = {
      rows: {
        appendable: false,
        selectable: { multiple: true }
      },
      pagination: { infinite: true },
      columns: [
        { type: 'gutter', gutterName: 'row-selector', multiple: true },
        {
          type: 'string',
          name: 'batchId',
          header: i18next.t('field.batch_id'),
          width: 100
        },
        {
          type: 'string',
          name: 'productSku',
          header: i18next.t('field.sku'),
          width: 150
        },
        {
          type: 'date',
          name: 'manufactureDate',
          header: i18next.t('field.manufacture_date'),
          width: 150
        },
        {
          type: 'integer',
          name: 'packQty',
          header: i18next.t('field.qty'),
          width: 60
        },
        {
          type: 'string',
          name: 'packingType',
          header: i18next.t('field.packing_type'),
          width: 120
        },
        {
          type: 'integer',
          name: 'printQty',
          header: i18next.t('field.print_qty'),
          record: { editable: true, options: { min: 1 } },
          width: 80
        }
      ]
    }
  }

  render() {
    return html `
      ${this.enableDirectInbound
        ? this.renderDirectInboundPrintLayout()
        : html`
            <div id="input-form" class="single-column-form">
              <label>${i18next.t('label.printing_mode')}</label>
              ${this.filterContent()}
            </div>
            ${this.printControl()}
            <div class="button-container">
              <mwc-button raised @click="${this._printLabel.bind(this)}" label="${i18next.t('button.print')}"></mwc-button>
            </div>
          `}
    `
  }

  filterContent() {
    if (this.fixedType) this._filters = this._filters.filter(filter => filter.value == this.fixedType)

    return html`
      <select
        name="printType"
        @change="${e => {
          this.type = e.currentTarget.value
        }}"
      >
        ${this._filters.map(filter => html` <option value="${filter.value}">${filter.name}</option> `)}
      </select>
    `
  }

  _fieldChange(e) {
    var { after, before, column, record, row } = e.detail

    if (column.record?.options?.min > after) {
      this.dataGrist._data.records[row][column.name] = before
      this.data = {
        ...this.dataGrist._data
      }
      this._showToast({ message: `Minimum value of ${column.record.options.min} is required.` })
    }
  }

  printControl() {
    switch (this.type) {
      case 'bySku':
        this.data.records = this.data.records.map(record => {
          record.printQty = record.packQty
          return record
        })
        return html`
          <div class="container">
            <div class="grist">
              <data-grist
                id="grist"
                .mode=${'GRID'}
                .config=${this._config}
                .data="${this.data}"
                @field-change="${this._fieldChange.bind(this)}"
              ></data-grist>
            </div>
          </div>
        `
      default:
        return html`
          <div class="single-column-form">
            <label>${i18next.t('label.print_qty')}</label>
            <input name="printQty" type="number" min="1" />
          </div>
        `
    }
  }

  renderDirectInboundPrintLayout() {
    return html`
      <div class = "form-container">
        <form name="printPopup" class="multi-column-form">
          <fieldset>
            <legend>${i18next.t('Print Settings')}</legend>
          </fieldset>
          
          <div class="form-container">
            <label>${i18next.t('label.print_qty')}</label>
            <input name="printQty" type="number" min="1" />
          </div>
        </form>
      </div>

      <div class="container">
        <div class="grist">
          <h2><mwc-icon>list_alt</mwc-icon>Select Product</h2>
          <data-grist
            id="product-grist"
            .mode=${'GRID'}
            .config=${this.productGristConfig}
            .data="${this.productData}"
          ></data-grist>
        </div>
      </div>

      <div class="button-container">
        <mwc-button raised @click="${this._printLabel.bind(this)}" label="${i18next.t('button.print')}"></mwc-button>
      </div>
    `
  }

  setProductGristConfig() {
    let productGristColumns = [
      { type: 'gutter', gutterName: 'sequence' },
      { type: 'gutter', gutterName: 'row-selector', multiple: true},
      {
        type: 'string',
        name: 'cartonId',
        header: i18next.t('field.carton_id'),
        width: 150
      },
      {
        type: 'string',
        name: 'batchId',
        header: i18next.t('field.batch_id'),
        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: 'uom',
        header: i18next.t('field.uom'),
        width: 80
      },
      {
        type: 'float',
        name: 'uomValue',
        header: i18next.t('field.uom_value'),
        width: 100
      },
      {
        type: 'float',
        name: 'packQty',
        header: i18next.t('field.pack_qty'),
        width: 80
      }
    ]

    this.productGristConfig = {
      list: {
        fields: [
          'cartonId',
          'batchId',
          'product',
          'packingType',
          'uom',
          'uomValue',
          'packQty'
        ]
      },
      pagination: { infinite: true },
      rows: {
        appendable: false
      },
      columns: productGristColumns
    }
  }

  async fetchInventories() {
  if (!this.arrivalNoticeId) return

  const response = await client.query({
    query: gql`
      query ($filters: [Filter!]) {
        inventories(filters: $filters) {
          items {
            cartonId
            batchId
            packingType
            uom
            uomValue
            qty
            product {
              id
              name
              sku
            }
          }
        }
      }
    `,
    variables: {
      filters: [
        {
          name: 'refOrderId',
          operator: 'eq',
          value: this.arrivalNoticeId
        }
      ]
    },
    fetchPolicy: 'no-cache'
  })

  const inventories = response?.data?.inventories?.items || []

  // Optional: transform into productData format expected by the Grist
  this.productData = {
    records: inventories.map(item => ({
      cartonId: item.cartonId,
      batchId: item.batchId,
      packingType: item.packingType,
      uom: item.uom,
      uomValue: item.uomValue,
      packQty: item.qty,
      product: item.product
    }))
  }
}


  async _printLabel() {
    if (!this._printer) {
      this._printer = new DirectPrinter()
    }

    if (this.enableDirectInbound) {
      this.type = 'directInboundBySku'
    }

    try {
      const filters = this._filters
      let labelId = filters.find(itm => itm.value == (this?.type ? this.type : 'default')).board.id
      let bizplaceName = this.bizplaceName
      let printData = []

      switch (this.type) {
        case 'directInboundBySku':
          let selectedRows = this.shadowRoot.querySelector('data-grist')?.selected || []
          const printQtyVal = parseInt(this.printQtyInput?.value) || 1

          if (selectedRows.length > 0) {
            selectedRows.forEach(obj => {
              for (let index = 0; index < printQtyVal; index++) {
                const manufactureDate = new Date(obj.manufactureDate)
                const manufactureYear = manufactureDate.getFullYear()

                let data = {
                  batchId: obj.batchId,
                  productSku: obj.product?.sku || obj.productSku,
                  packingType: obj.packingType,
                  packQty: obj.packQty,
                  printQty: printQtyVal,
                  manufactureDate: manufactureDate.toLocaleDateString(),
                  manufactureYear: manufactureYear.toString(),
                  cartonId: obj.cartonId,
                  customer: bizplaceName,
                  printCount: index + 1,
                  carton: obj.cartonId
                }

                printData.push(data)
              }
            })

            await sendToPrinter(labelId, printData, this._printer)
          }
          break

        case 'bySku':
          let selected = this.dataGrist.selected

          if (selected.length > 0) {

            const cartonLabels = await this._getCartonId(selected.length)

            selected.forEach((obj, idx) => {
              for (let index = 0; index < obj.printQty; index++) {
                let manufactureDate = new Date(obj.manufactureDate);
                let manufactureYear = manufactureDate.getFullYear(); 

                let data = {
                  batchId: obj.batchId,
                  productSku: obj.productSku,
                  packingType: obj.packingType,
                  packQty: obj.packQty,
                  printQty: obj.printQty,
                  refNo: obj.refNo,
                  refNo2: obj.refNo2,
                  refNo3: obj.refNo3,
                  manufactureDate: manufactureDate.toLocaleDateString(),
                  manufactureYear: manufactureYear.toString(),
                  cartonId: cartonLabels[idx].cartonId,
                  customer: bizplaceName,
                  printCount: index + 1,
                  carton: cartonLabels[idx].cartonId
                             }
              printData.push(data);
              }
            })
            await sendToPrinter(labelId, printData, this._printer)
          }
          break
        default:
          const printQty = this.printQtyInput?.value
          if (isNaN(printQty) || printQty < 1) {
            throw new Error(i18next.t('text.invalid_print_qty'))
          }

          const results = await this._getCartonId(printQty)

          for (let i = 0; i < results.length; i++) {
            let data = {
              cartonId: results[i].cartonId,
              customer: bizplaceName
            }
            printData.push(data)
          }
          await sendToPrinter(labelId, printData, this._printer)
      }
    } catch (e) {
      delete this._printer
      this._showToast(e)
    }
  }

  async _getCartonId(printQty) {
    const response = await client.query({
      query: gql`
        query generateCartonId($printQty: Int!, $type: String!) {
          generateCartonId(printQty: $printQty, type: $type) {
            cartonId
          }
        }
      `,
      variables: { printQty: parseInt(printQty), type: 'inbound_carton_id' }
    })

    if (!response.errors) {
      return response.data.generateCartonId
    } else {
      throw new Error('Unable to Generate Carton Id')
    }
  }

  stateChanged(state) {
    let filters = [
      { name: i18next.t(`label.normal`), value: 'default', labelId: CARTON_LABEL_SETTING_KEY },
      { name: i18next.t(`label.print_by_sku`), value: 'bySku', labelId: CARTON_LABEL_BY_SKU_SETTING_KEY },
      { name: 'Direct Inbound by SKU', value: 'directInboundBySku', labelId: CARTON_LABEL_BY_SKU_SETTING_KEY}
    ]

    this._filters = filters
      .map(filter => {
        let setting = state.dashboard[filter.labelId]
        return { ...filter, board: setting?.board || null }
      })
      .filter(filter => filter.board)
  }

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

window.customElements.define('carton-label-popup', CartonLabelPopup)
