import '@things-factory/form-ui'
import '@things-factory/grist-ui'
import './print-quantity-popup'

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

import { i18next, localize } from '@things-factory/i18n-base'
import { openPopup } from '@things-factory/layout-base'
import { client } from '@things-factory/shell'
import { ScrollbarStyles } from '@things-factory/styles'
import { isMobileDevice } from '@things-factory/utils'

import { showToast } from '../../../util'

class PackingLabelHistoryPopup extends localize(i18next)(LitElement) {
  static get properties() {
    return {
      _searchFields: Array,
      config: Object,
      data: Object,
      _packingLabelOptions: Array
    }
  }

  static get styles() {
    return [
      ScrollbarStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow: hidden;
          background-color: white;
        }

        search-form {
          overflow: visible;
        }

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

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

  constructor() {
    super()
    this._packingLabelOptions = []
  }

  get searchForm() {
    return this.shadowRoot.querySelector('search-form')
  }

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

  _initSearchFields() {
    this._searchFields = [
      {
        label: i18next.t('field.order_no') || 'Order No.',
        name: 'releaseGood.name',
        type: 'text',
        props: { searchOper: 'i_like' }
      },
      {
        label: i18next.t('field.packing_label_no'),
        name: 'displayNumber',
        type: 'select',
        options: this._packingLabelOptions,
        props: { searchOper: 'eq' }
      }
    ]
  }

  _initConfig() {
    this.config = {
      rows: { selectable: { multiple: true }, appendable: false },
      list: { fields: ['releaseGood', 'refNo', 'displayNumber', 'printedAt'] },
      pagination: { limit: 50, pages: [20, 50, 100, 200] },
      columns: [
        { type: 'gutter', gutterName: 'sequence' },
        { type: 'gutter', gutterName: 'row-selector', multiple: true },
        {
          type: 'gutter',
          gutterName: 'button',
          icon: 'reorder',
          handlers: {
            click: (_columns, _data, _column, record) => {}
          }
        },
        {
          type: 'object',
          name: 'releaseGood',
          header: i18next.t('field.order_no') || 'Release Orders',
          sortable: true,
          width: 180
        },
        {
          type: 'string',
          name: 'refNo',
          header: i18next.t('field.ref_no') || 'Ref No.',
          sortable: true,
          width: 150
        },
        {
          type: 'number',
          name: 'displayNumber',
          header: i18next.t('field.packing_label_no') || 'Packing Label No.',
          sortable: true,
          width: 120
        },
        {
          type: 'datetime',
          name: 'printedAt',
          header: i18next.t('field.printed_at') || 'Printed At',
          sortable: true,
          width: 160
        },
        {
          type: 'object',
          name: 'printedBy',
          header: i18next.t('field.printed_by') || 'Printed By',
          sortable: true,
          width: 160
        }
      ]
    }
  }

  async firstUpdated() {
    await this._fetchPackingLabelOptions()
    this._initSearchFields()
    this._initConfig()
  }

  async _fetchPackingLabelOptions() {
    try {
      const response = await client.query({
        query: gql`
          query {
            maxPackingLabelCount
          }
        `
      })

      if (!response.errors) {
        const maxCount = response.data.maxPackingLabelCount || 0
        this._packingLabelOptions = [
          { value: '', name: '' },
          ...Array.from({ length: maxCount }, (_, i) => ({
            value: String(i + 1),
            name: String(i + 1)
          }))
        ]
      }
    } catch (e) {
      console.error('Failed to fetch packing label options:', e)
      this._packingLabelOptions = [{ value: '', name: '' }]
    }
  }

  async fetchHandler({ page, limit, sorters = [] }) {
    const filters = this.searchForm.queryFilters
    
    const response = await client.query({
      query: gql`
        query printedLoadingPackagesHistory($filters: [Filter!], $pagination: Pagination, $sortings: [Sorting!]) {
          printedLoadingPackagesHistory(filters: $filters, pagination: $pagination, sortings: $sortings) {
            items {
              id
              name
              displayNumber
              releaseGood {
                id
                name
                refNo
              }
              printedAt
              printedBy {
                id
                name
                description
              }
            }
            total
          }
        }
      `,
      variables: {
        filters,
        pagination: { page, limit },
        sortings: sorters
      }
    })

    if (!response.errors) {
      return {
        total: response.data.printedLoadingPackagesHistory.total || 0,
        records:
          response.data.printedLoadingPackagesHistory.items.map(item => ({
            ...item,
            refNo: item.releaseGood?.refNo || ''
          })) || []
      }
    }

    return { total: 0, records: [] }
  }

  _handlePrint() {
    try {
      const selected = this.dataGrist.selected || []
      if (selected.length === 0) {
        showToast({
          type: 'warning',
          message: i18next.t('text.please_select_at_least_one_record') || 'Please select at least one record'
        })
        return
      }

      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._executePrint(selected, printQuantity)
            }}"
          ></print-quantity-popup>
        `,
        {
          backdrop: true,
          size: 'small',
          title: i18next.t('title.print_packing_label') || 'Print Packing Label'
        }
      )
    } catch (e) {
      showToast({ type: 'error', message: e.message || i18next.t('text.failed_to_print') })
    }
  }

  async _executePrint(selected, printQuantity) {
    const loadingPackageIds = selected.map(item => item.id).filter(Boolean)

    if (loadingPackageIds.length === 0) {
      showToast({ type: 'error', message: i18next.t('text.no_valid_packages_selected') || 'No valid packages selected' })
      return
    }

    try {
      const response = await fetch('/render_packing_label', {
        method: 'POST',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          loadingPackageIds,
          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)
      this.dataGrist.fetch()
    } catch (error) {
      console.error('Print error:', error)
      showToast({ type: 'error', message: error.message || i18next.t('text.failed_to_print') || 'Failed to print' })
    }
  }

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

      iframe.onload = () => {
        try {
          iframe.contentWindow.focus()
          iframe.contentWindow.print()
          resolve()
        } catch (e) {
          reject(e)
        }
      }

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

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

  _closePopup() {
    history.back()
  }

  render() {
    return html`
      <search-form
        id="search-form"
        .fields=${this._searchFields}
        @submit=${() => this.dataGrist.fetch()}
      ></search-form>

      <div class="grist-container">
        <div class="grist">
          <data-grist
            .mode=${isMobileDevice() ? 'LIST' : 'GRID'}
            .config=${this.config}
            .fetchHandler=${this.fetchHandler.bind(this)}
          ></data-grist>
        </div>
      </div>

      <div class="button-container">
        <mwc-button @click=${this._closePopup}>${i18next.t('button.close')}</mwc-button>
        <mwc-button raised @click=${this._handlePrint}>${i18next.t('button.print')}</mwc-button>
      </div>

      <iframe id="print-iframe" style="display: none;"></iframe>
    `
  }
}

window.customElements.define('packing-label-history-popup', PackingLabelHistoryPopup)
