import '@things-factory/barcode-ui'
import '@things-factory/grist-ui'
import './show-my-loading-worksheet-list-popup'
import './loading-execution'
import '../show-ro-list-popup'
import { fetchSettingRule } from '../../../fetch-setting-value'

import gql from 'graphql-tag'
import { css, html, property } from 'lit-element'
import { connect } from 'pwa-helpers/connect-mixin.js'
import { sleep } from '@things-factory/utils'
import { MultiColumnFormStyles, SingleColumnFormStyles } from '@things-factory/form-ui'
import { i18next, localize } from '@things-factory/i18n-base'
import { openPopup } from '@things-factory/layout-base'
import { client, gqlContext, PageView, store } from '@things-factory/shell'
import { CommonButtonStyles } from '@things-factory/styles'
import { isMobileDevice } from '@things-factory/utils'

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

// Constants
const SETTINGS = {
  QC_SKU: 'qc-sku',
  DISABLE_QC: 'disable-QC-in-loading'
}

const FILTER_TYPES = {
  QC: 'qc',
  LOADING: 'loading',
  ALL: 'all'
}

// GraphQL Queries
const FIND_LOADABLE_RELEASE_GOOD = gql`
  query findLoadableReleaseGood($orderNo: String!, $tabName: String!) {
    findLoadableReleaseGood(orderNo: $orderNo, tabName: $tabName) {
      id
      name
      refNo
      refNo2
      status
      district
      attentionCompany
      attentionTo
      deliveryAddress1
      deliveryAddress2
      deliveryAddress3
      deliveryAddress4
      deliveryAddress5
      sortedBy {
        name
      }
      itemCounts {
        total
        pending
      }
      tabCounts {
        LOADING {
          total
          completed
          pending
        }
        LOADED {
          total
          completed
          pending
        }
      }
    }
  }
`

const FIND_LOADABLE_RELEASE_GOOD_BY_BIN = gql`
  query findLoadableReleaseGoodByBin($orderNo: String!) {
    findLoadableReleaseGoodByBin(orderNo: $orderNo) {
      worksheetInfo {
        worksheet {
          id
          name
          type
          status
        }
        bizplaceName
        startedAt
        binLocationName
        isReleaseGoodScan
        releaseGood {
          id
          name
          attentionCompany
          status
          attentionTo
          deliveryAddress1
          deliveryAddress2
          refNo
          refNo2
          refNo3
          rtm
        }
      }
      worksheetDetailInfos {
        id
        name
        batchId
        releaseQty
        pickedQty
        sortedQty
        status
        packingType
        packingSize
        conversion
        expirationDate
        binLocation {
          name
        }
        productName
        productSku
        relatedOrderInv {
          id
          batchId
          packingType
          refWorksheetId
          packedQty
          releaseQty
          product {
            id
            sku
            name
            isInventoryDecimal
          }
          productDetail {
            id
            productBarcodes {
              gtin
            }
          }
          orderProduct {
            id
          }
        }
      }
    }
  }
`

const LOADING_WORKSHEET_V2 = gql`
  query loadingWorksheetv2($orderNo: String!, $filter: String) {
    loadingWorksheetv2(orderNo: $orderNo, filter: $filter) {
      worksheetInfo {
        worksheet {
          id
          name
          type
          status
        }
        bizplaceName
        startedAt
        releaseGood {
          id
          name
          attentionCompany
          attentionTo
          deliveryAddress1
          deliveryAddress2
          status
          refNo
          refNo2
          refNo3
          remark
          rtm
        }
      }
      worksheetDetailInfos {
        id
        name
        batchId
        releaseQty
        pickedQty
        sortedQty
        status
        packingType
        packingSize
        conversion
        expirationDate
        binLocation {
          name
        }
        productName
        productSku
        relatedOrderInv {
          id
          batchId
          packingType
          refWorksheetId
          packedQty
          releaseQty
          product {
            id
            sku
            name
            isInventoryDecimal
          }
          productDetail {
            id
            productBarcodes {
              gtin
            }
          }
          orderProduct {
            id
          }
        }
      }
    }
  }
`

const GET_DELIVERY_ORDERS = gql`
  query getDeliveryOrders($releaseGoodNo: String!) {
    getDeliveryOrders(releaseGoodNo: $releaseGoodNo) {
      completable
      deliveryOrders {
        id
        name
        truckNo
        orderInventories {
          batchId
          packingSize
          packingType
          pickedQty
          product {
            name
            sku
          }
          inventory {
            expirationDate
          }
        }
      }
    }
  }
`

const GET_LOADING_TASK = gql`
  mutation getLoadingTask {
    getLoadingTask {
      worksheetInfo {
        worksheet {
          id
          name
          type
          status
        }
        bizplaceName
        startedAt
        releaseGood {
          id
          name
          attentionCompany
          status
          refNo
          refNo2
          refNo3
          remark
          rtm
        }
      }
      worksheetDetailInfos {
        id
        name
        batchId
        releaseQty
        pickedQty
        sortedQty
        status
        packingType
        packingSize
        conversion
        expirationDate
        binLocation {
          name
        }
        productName
        productSku
        relatedOrderInv {
          id
          batchId
          packingType
          refWorksheetId
          packedQty
          releaseQty
          product {
            id
            sku
            name
            isInventoryDecimal
          }
          productDetail {
            id
            productBarcodes {
              gtin
            }
          }
          orderProduct {
            id
          }
        }
      }
    }
  }
`

class LoadingProductV2 extends connect(store)(localize(i18next)(PageView)) {
  static get properties() {
    return {
      _state: Object,
      _data: Object,
      _context: Object,
      _qcSku: Boolean,
      _disableQC: Boolean,
      _tabCounts: Object
    }
  }

  @property() _context = {
    title: i18next.t('title.loading'),
    help: 'operato-wms/outbound/loading-product-2'
  }

  static get styles() {
    return [
      MultiColumnFormStyles,
      SingleColumnFormStyles,
      css`
        :host {
          display: flex;
          flex-direction: column;
          overflow: hidden;
          padding: 0;
        }
        data-grist {
          overflow: auto;
          flex: 1;
        }
        h2 {
          padding: var(--subtitle-padding);
          font: var(--subtitle-font);
          color: var(--subtitle-text-color);
          border-bottom: var(--subtitle-border-bottom);
        }
        legend mwc-icon {
          vertical-align: middle;
          margin: var(--grist-title-icon-margin);
          font-size: var(--grist-title-icon-size);
          color: var(--grist-title-icon-color);
          cursor: pointer;
        }
        #order-form {
          grid-column: span 12;
          padding: 0 10px;
        }

        @media screen and (max-width: 460px) {
          .single-column-form {
            max-width: 100%;
            grid-gap: 5px;
          }
        }
      `
    ]
  }

  constructor() {
    super()
    this.configContext()
    this._qcSku = false
    this._disableQC = false
    this.initializeSettings()
  }

  async initializeSettings() {
    try {
      this._qcSku = await fetchSettingRule(SETTINGS.QC_SKU)
      this._disableQC = await fetchSettingRule(SETTINGS.DISABLE_QC)
      this.configContext()
    } catch (e) {
      console.error('Error initializing settings:', e)
    }
  }

  configContext(
    actions = [
      {
        title: i18next.t('button.get_task'),
        action: this.getTask.bind(this),
        ...CommonButtonStyles.assignment
      },
      {
        title: i18next.t('button.my_worksheet'),
        action: this.showWorksheetList.bind(this),
        ...CommonButtonStyles.inspect
      }
    ]
  ) {
    if (this._qcSku) {
      actions = actions.filter(a => a.title !== i18next.t('button.get_task'))
    }
    this._context = {
      ...this._context,
      actions
    }
    this.updateContext()
  }

  get context() {
    return this._context
  }

  get orderNoInput() {
    return this.shadowRoot.querySelector('barcode-scanable-input[name=orderNo]')?.shadowRoot.querySelector('input')
  }

  render() {
    if (this._data) {
      return html` <loading-execution
        .parent=${this}
        .worksheet=${this._data.worksheetInfo}
        .worksheetDetails=${this._data?.worksheetDetailInfos}
        .deliveryOrdersInfo=${this._data?.deliveryOrderInfoList}
        ._useQcSku=${this._qcSku}
        ._tabCounts=${this._tabCounts}
      ></loading-execution>`
    } else {
      return html` <div class="${isMobileDevice() ? 'single-column-form' : 'multi-column-form'}">
        <form id="order-form">
          <fieldset>
            <legend>${i18next.t('title.scan')}</legend>
            <label>${i18next.t('label.order_no') + ' / ' + i18next.t('label.bin_no')}</label>
            <barcode-scanable-input
              name="orderNo"
              custom-input
              @keypress="${async e => {
                try {
                  if (e.keyCode === 13) {
                    e.preventDefault()
                    await this.fetchOrder(this.orderNoInput.value)
                  }
                } catch (e) {}
              }}"
            >
            </barcode-scanable-input>
          </fieldset>
        </form>
      </div>`
    }
  }

  async getTask() {
    try {
      const response = await client.mutate({
        mutation: GET_LOADING_TASK,
        variables: {},
        context: gqlContext()
      })

      if (!response.errors) {
        let data = response.data.getLoadingTask
        data.deliveryOrderInfoList = await this.fetchDeliveryOrders(data.worksheetInfo.releaseGood.name)
        this._data = data
      }
    } catch (e) {
      showToast(e)
    }

    this.updateContext()
  }

  async fetchOrder(orderNo) {
    try {
      // Use FIND_LOADABLE_RELEASE_GOOD if:
      // 1. qc-sku is false, OR
      // 2. qc-sku is true but disable-QC-in-loading is true (QC tab is hidden, so use order number scanning)
      const shouldUseOrderNumberQuery = !this._qcSku || this._disableQC === true || this._disableQC === 'true'

      if (shouldUseOrderNumberQuery) {
        const defaultTabName = this._disableQC === true || this._disableQC === 'true' ? 'LOADING' : 'QC'

        const response = await client.query({
          query: FIND_LOADABLE_RELEASE_GOOD,
          variables: {
            orderNo,
            tabName: defaultTabName
          },
          context: gqlContext(),
          fetchPolicy: 'network-only' // Always fetch fresh data to show updated item counts
        })

        if (!response.errors) {
          let records = response.data.findLoadableReleaseGood

          if (records.length) {
            await this.selectReleaseOrderPopup(records)
          } else {
            throw new Error(i18next.t('text.no_release_order_found'))
          }
        }
      } else {
        // Use FIND_LOADABLE_RELEASE_GOOD_BY_BIN when qc-sku is true and QC is enabled
        const response = await client.query({
          query: FIND_LOADABLE_RELEASE_GOOD_BY_BIN,
          variables: { orderNo },
          context: gqlContext()
        })

        if (!response.errors) {
          let items = response.data.findLoadableReleaseGoodByBin
          this._data = items
        }
      }
    } catch (e) {
      showToast(e)
    }
  }

  async selectReleaseOrderPopup(orders) {
    let releaseGoods = orders.map(ro => {
      const addressParts = [
        ro.deliveryAddress1,
        ro.deliveryAddress2,
        ro.deliveryAddress3,
        ro.deliveryAddress4,
        ro.deliveryAddress5
      ].filter(addr => addr && addr.trim() !== '')
       .map(addr => addr.trim().replace(/,+\s*$/, ''))
      
      return {
        ...ro,
        sortedByUser: ro.sortedBy?.name,
        address: addressParts.join(', ')
      }
    })

    await sleep(1010)
    openPopup(
      html`
        <show-ro-list-popup
          .releaseOrders=${releaseGoods}
          .sorting=${false}
          @ro-selected-loading=${async e => {
            const selectedRO = e.detail.ro
            // Store tabCounts for passing to loading-execution component
            if (selectedRO?.tabCounts) {
              this._tabCounts = selectedRO.tabCounts
            }
            // Ensure settings are loaded before fetching worksheet to use correct filter
            if (this._disableQC === undefined || this._disableQC === null) {
              await this.initializeSettings()
            }
            await this.fetchWorksheet(selectedRO?.name)
          }}
        ></show-ro-list-popup>
      `,
      {
        backdrop: true,
        size: 'medium',
        title: i18next.t('title.release_orders')
      }
    )
  }

  async fetchWorksheet(orderNo) {
    try {
      // Ensure settings are loaded before determining filter
      // fetchSettingRule returns boolean true/false, so check for boolean true
      const disableQC = this._disableQC === true

      // Fetch BOTH QC and LOADING data so the banner can properly determine state
      // This ensures loadingData is available even when QC is complete
      const [qcResponse, loadingResponse] = await Promise.all([
        client.query({
          query: LOADING_WORKSHEET_V2,
          variables: { orderNo, filter: FILTER_TYPES.QC },
          fetchPolicy: 'network-only'
        }),
        client.query({
          query: LOADING_WORKSHEET_V2,
          variables: { orderNo, filter: FILTER_TYPES.LOADING },
          fetchPolicy: 'network-only'
        })
      ])

      if (!qcResponse.errors && !loadingResponse.errors) {
        const qcData = qcResponse.data?.loadingWorksheetv2
        const loadingData = loadingResponse.data?.loadingWorksheetv2

        // Combine worksheetDetailInfos from both queries, removing duplicates by id
        const qcDetails = qcData?.worksheetDetailInfos || []
        const loadingDetails = loadingData?.worksheetDetailInfos || []
        const detailsMap = new Map()

        // Add QC details first
        qcDetails.forEach(detail => {
          if (detail?.id) detailsMap.set(detail.id, detail)
        })
        // Add loading details (will overwrite duplicates)
        loadingDetails.forEach(detail => {
          if (detail?.id) detailsMap.set(detail.id, detail)
        })

        // Use worksheetInfo from whichever has it (prefer QC, fallback to loading)
        let items = {
          worksheetInfo: qcData?.worksheetInfo || loadingData?.worksheetInfo,
          worksheetDetailInfos: Array.from(detailsMap.values())
        }
        items.deliveryOrderInfoList = await this.fetchDeliveryOrders(orderNo)
        this._data = items
      }
    } catch (e) {
      showToast(e)
    }
  }

  async fetchDeliveryOrders(releaseGoodName) {
    try {
      const response = await client.query({
        query: GET_DELIVERY_ORDERS,
        variables: { releaseGoodNo: releaseGoodName }
      })

      if (!response.errors) {
        return response.data.getDeliveryOrders
      }
    } catch (e) {
      showToast(e)
    }
  }

  async showWorksheetList() {
    await sleep(1010)
    openPopup(
      html` <show-my-loading-worksheet-list-popup .type=${'LOADING'}></show-my-loading-worksheet-list-popup> `,
      {
        backdrop: true,
        size: 'small',
        title: i18next.t('title.my_worksheet_list')
      }
    )
  }
}

window.customElements.define('loading-product-v2', LoadingProductV2)
