import '@things-factory/grist-ui'
import '@things-factory/barcode-ui'

import gql from 'graphql-tag'
import { css, html } from 'lit-element'

import { MultiColumnFormStyles } from '@things-factory/form-ui'
import { i18next, localize } from '@things-factory/i18n-base'
import { client, PageView, gqlContext } from '@things-factory/shell'
import { CommonButtonStyles } from '@things-factory/styles'
import { isMobileDevice } from '@things-factory/utils'
import { openPopup } from '@things-factory/layout-base'

import { showToast } from '../../../util'
import './print-quantity-popup'

class PreviewPrintPackingList extends localize(i18next)(PageView) {
  constructor() {
    super()
    this.orderNos = []
    this.releaseOrders = []
    this.loadingPackagesMap = {}
  }

  static get properties() {
    return {
      packingListConfig: Object,
      orderNos: Array,
      releaseOrders: Array,
      loadingPackagesMap: Object
    }
  }

  static get styles() {
    return [
      MultiColumnFormStyles,
      css`
        :host {
          overflow-x: auto;
        }
        section {
          display: flex;
          flex-direction: column;
          margin-bottom: 20px;
        }
        .form-container {
          display: flex;
        }
        .form-container > form {
          flex: 1;
        }
        barcode-tag {
          width: 100px;
          height: 100px;
          margin: 10px;
        }
        .grist {
          background-color: var(--main-section-background-color);
          display: flex;
          flex-direction: column;
          flex: 1;
          overflow-y: auto;
        }
        .grist-column {
          flex: 1;
          display: flex;
          flex-direction: column;
          overflow: 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);
        }
        .grist h2 {
          margin: var(--grist-title-margin);
          border: var(--grist-title-border);
          font: var(--grist-title-font);
          color: var(--secondary-color);
          text-transform: capitalize;
        }

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

        .print-iframe {
          position: absolute;
          left: -9999px;
          top: -9999px;
          width: 0;
          height: 0;
          border: none;
          visibility: hidden;
        }
      `
    ]
  }

  get context() {
    var actions = [
      {
        title: i18next.t('button.back_to_list'),
        action: () => history.back(),
        ...CommonButtonStyles.back
      },
      {
        title: i18next.t('button.print') || 'Print',
        action: this._openPrintQuantityPopup.bind(this),
        ...CommonButtonStyles.print,
        emphasis: {
          ...CommonButtonStyles.activate.emphasis
        }
      }
    ]

    return {
      title: i18next.t('title.release_orders'),
      actions,
    }
  }

  _openPrintQuantityPopup() {
    openPopup(
      html`
        <print-quantity-popup
          @print="${e => {
            const printQuantity = e.detail.printQuantity
            
            // Validate print quantity
            if (!printQuantity || printQuantity <= 0) {
              showToast({
                type: 'error',
                message: i18next.t('text.print_qty_must_be_at_least_one') || 'Print quantity must be at least 1'
              })
              return
            }
            
            // Close popup and execute print
            history.back()
            this._handlePrint(printQuantity)
          }}"
        ></print-quantity-popup>
      `,
      {
        backdrop: true,
        size: 'small',
        title: i18next.t('title.print_packing_label') || 'Print Packing Label'
      }
    )
  }

  async _handlePrint(printQuantity) {
    if (!this.orderNos?.length) {
      showToast({ type: 'warning', message: i18next.t('text.no_data_to_print') || 'No data to print' })
      return
    }

    try {
      const response = await fetch('/render_packing_label', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          releaseGoodNos: this.orderNos,
          printQuantity: Math.max(1, parseInt(printQuantity) || 1)
        })
      })

      if (!response.ok) {
        const errorText = await response.text()
        throw new Error(errorText || `Failed to render packing label: ${response.statusText}`)
      }

      const renderedHtml = await response.text()
      if (!renderedHtml) {
        showToast({ type: 'error', message: i18next.t('text.failed_to_render_template') || 'Failed to render template' })
        return
      }

      await this._printViaIframe(renderedHtml)
    } catch (error) {
      console.error('Print error:', error)
      showToast({ type: 'error', message: error.message || 'Print failed' })
    }
  }

  async _printViaIframe(htmlContent) {
    return new Promise((resolve, reject) => {
      const iframe = this._printIframe
      if (!iframe) {
        reject(new Error('Print iframe not found'))
        return
      }

      const handleLoad = () => {
        iframe.removeEventListener('load', handleLoad)
        try {
          iframe.contentWindow.print()
          resolve()
        } catch (error) {
          reject(error)
        }
      }

      iframe.addEventListener('load', handleLoad)

      const iframeDoc = iframe.contentDocument || iframe.contentWindow.document
      iframeDoc.open()
      iframeDoc.write(htmlContent)
      iframeDoc.close()
    })
  }

  get _printIframe() {
    return this.shadowRoot?.querySelector('#print-iframe')
  }

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

  async pageInitialized(lifecycle) {
    this.packingListConfig = {
      pagination: { limit: 50, pages: [50, 100, 200, 500, 1000] },
      rows: { appendable: false },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        {
          type: 'string',
          name: 'sku',
          header: i18next.t('field.sku'),
          width: 120
        },
        {
          type: 'string',
          name: 'productName',
          header: i18next.t('field.name'),
          width: 180
        },
        {
          type: 'string',
          name: 'packingType',
          header: i18next.t('field.packing_type'),
          width: 150
        },
        {
          type: 'number',
          name: 'packingSize',
          header: i18next.t('field.packing_size'),
          width: 140
        },
        {
          type: 'number',
          name: 'packedQty',
          header: i18next.t('field.qty'),
          width: 130
        },
        {
          type: 'float',
          name: 'uomValue',
          header: i18next.t('field.uom_value'),
          width: 150
        },
        {
          type: 'string',
          name: 'uom',
          header: i18next.t('field.uom'),
          width: 80
        }
      ]
    }

    // Also check for URL params in pageInitialized
    await this.updateComplete
    if (this.active && lifecycle?.params?.orderNo) {
      this.orderNos = lifecycle.params.orderNo.split(',').filter(name => name.trim())
      await this.fetchReleaseOrders()
    }
  }

  async pageUpdated(changes, lifecycle) {
    if (this.active && lifecycle?.params?.orderNo) {
      const newOrderNos = lifecycle.params.orderNo.split(',').filter(name => name.trim())

      // Check if orderNos changed - re-fetch if different
      const currentOrderNos = this.orderNos || []
      const hasChanged =
        newOrderNos.length !== currentOrderNos.length ||
        newOrderNos.some((orderNo, idx) => orderNo !== currentOrderNos[idx])

      if (hasChanged) {
        this.orderNos = newOrderNos
        await this.fetchReleaseOrders()
      }
    }
  }

  async fetchReleaseOrders() {
    if (!this.orderNos?.length) return

    try {
      const loadingPackagesResponse = await client.query({
        query: gql`
            query loadingPackagesByReleaseGoodNos($releaseGoodNos: [String!]!) {
              loadingPackagesByReleaseGoodNos(releaseGoodNos: $releaseGoodNos) {
                  id
                  name
                  status
                  createdAt
                  releaseGood {
                    id
                    name
                    refNo
                    refNo2
                    refNo3
                    releaseDate
                    bizplace {
                      id
                      name
                    }
                  }
                  loadingPackageItems {
                    id
                    name
                    packedQty
                    orderProduct {
                      id
                      name
                      packingType
                      packingSize
                      uom
                      uomValue
                      product {
                        id
                        name
                        sku
                      }
                  }
                  productDetail {
                    id
                    packingType
                    packingSize
                    uom
                    uomValue
                  }
                }
              }
            }
          `,
        variables: { releaseGoodNos: this.orderNos },
        context: gqlContext()
      })

      if (!loadingPackagesResponse.errors && loadingPackagesResponse.data.loadingPackagesByReleaseGoodNos) {
        // Extract unique release orders from loading packages
        const releaseOrdersMap = new Map()
        const loadingPackagesMap = {}
        
        loadingPackagesResponse.data.loadingPackagesByReleaseGoodNos.forEach(pkg => {
          const releaseGood = pkg.releaseGood
          if (releaseGood && releaseGood.name) {
            const orderNo = releaseGood.name
            
            // Store release order details (will overwrite duplicates, but they should be the same)
            if (!releaseOrdersMap.has(orderNo)) {
              releaseOrdersMap.set(orderNo, releaseGood)
            }
            
            // Group loading packages by releaseGood name
            if (!loadingPackagesMap[orderNo]) {
              loadingPackagesMap[orderNo] = []
            }
            loadingPackagesMap[orderNo].push(pkg)
          }
        })
        
        // Convert map to array for releaseOrders
        this.releaseOrders = Array.from(releaseOrdersMap.values())
        
        // Ensure all orderNos have an entry (even if empty)
        this.orderNos.forEach(orderNo => {
          if (!loadingPackagesMap[orderNo]) {
            loadingPackagesMap[orderNo] = []
          }
          // If orderNo not in releaseOrders, add it with minimal data
          if (!releaseOrdersMap.has(orderNo)) {
            this.releaseOrders.push({
              name: orderNo,
              refNo: '',
              refNo2: '',
              refNo3: '',
              releaseDate: '',
              attentionTo: '',
              phone1: '',
              deliveryAddress1: '',
              remark: '',
              bizplace: { id: '', name: '' }
            })
          }
        })
        
        this.loadingPackagesMap = loadingPackagesMap
      } else {
        // Initialize empty map for all orders
        this.releaseOrders = this.orderNos.map(orderNo => ({
          name: orderNo,
          refNo: '',
          refNo2: '',
          refNo3: '',
          releaseDate: '',
          bizplace: { id: '', name: '' }
        }))
        this.loadingPackagesMap = this.orderNos.reduce((acc, orderNo) => {
          acc[orderNo] = []
          return acc
        }, {})
      }
    } catch (error) {
      console.error('Error fetching loading packages:', error)
      this.releaseOrders = this.orderNos.map(orderNo => ({
        name: orderNo,
        refNo: '',
        refNo2: '',
        refNo3: '',
        releaseDate: '',
        bizplace: { id: '', name: '' }
      }))
      this.loadingPackagesMap = this.orderNos.reduce((acc, orderNo) => {
        acc[orderNo] = []
        return acc
      }, {})
    }
  }

  _renderContent() {
    const releaseOrders = this.releaseOrders || []
    const loadingPackagesMap = this.loadingPackagesMap || {}

    return releaseOrders.map(releaseOrder => {
      const loadingPackages = loadingPackagesMap[releaseOrder.name] || []

      if (loadingPackages.length == 0) { return html`` }
      
      return html`
        <section>
          <div class="form-container">
            <form name="releaseOrder" class="multi-column-form">
              <fieldset>
                <legend>${i18next.t('title.release_order_no')}: ${releaseOrder.name}</legend>
                
                <label>${i18next.t('label.company')}</label>
                <input name="bizplaceName" value="${releaseOrder?.bizplace?.name || ''}" readonly />

                <label>${i18next.t('label.ref_no')}</label>
                <input name="refNo" value="${releaseOrder?.refNo || ''}" readonly />

                <label>${i18next.t('label.ref_no_2')}</label>
                <input name="refNo2" value="${releaseOrder?.refNo2 || ''}" readonly />

                <label>${i18next.t('label.ref_no_3')}</label>
                <input name="refNo3" value="${releaseOrder?.refNo3 || ''}" readonly />

                <label>${i18next.t('label.release_date')}</label>
                <input name="releaseDate" type="date" value="${releaseOrder.releaseDate || ''}" readonly />
              </fieldset>
            </form>

            <barcode-tag bcid="qrcode" .value=${releaseOrder.name} showLogo="true"></barcode-tag>
          </div>

          ${loadingPackages.length > 0
            ? html`
                ${loadingPackages.map((loadingPackage, packageIndex) => {
                  const packageItems = loadingPackage.loadingPackageItems || []
                  const itemsData = {
                    records: packageItems.map(item => ({
                      id: item.id,
                      sku: item.orderProduct?.product?.sku || '',
                      productName: item.orderProduct?.product?.name || item.orderProduct?.name || '',
                      packingType: item.productDetail?.packingType || item.orderProduct?.packingType || '',
                      packingSize: item.productDetail?.packingSize || item.orderProduct?.packingSize || null,
                      packedQty: item.packedQty || 0,
                      uomValue: item.productDetail?.uomValue || item.orderProduct?.uomValue || null,
                      uom: item.productDetail?.uom || item.orderProduct?.uom || ''
                    })),
                    total: packageItems.length
                  }
                  
                  return html`
                    <div class="grist">
                      <h2>
                        <mwc-icon>inventory_2</mwc-icon>
                        ${i18next.t('title.packing_label')} ${packageIndex + 1}
                      </h2>
                      <data-grist
                        .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
                        .config=${this.packingListConfig}
                        .data=${itemsData}
                      ></data-grist>
                    </div>
                  `
                })}
              `
            : html``}
        </section>
      `
    })
  }

  render() {
    const content = this._renderContent()

    return html`
      ${content}
      <iframe id="print-iframe" class="print-iframe"></iframe>
    `
  }
}

window.customElements.define('preview-print-packing-list', PreviewPrintPackingList)