import { EntityManager, SelectQueryBuilder, getRepository } from 'typeorm'

import { User } from '@things-factory/auth-base'
import { Bizplace } from '@things-factory/biz-base'
import { ListParam, buildQuery, Domain } from '@things-factory/shell'
import { ReleaseGood } from '@things-factory/sales-base'

export const loadingQcReport = {
  async loadingQcReport(_: any, params: ListParam, context: any) {
    try {
      const { domain }: { domain: Domain } = context.state

      let bizplaceFilter = params.filters.find(filter => filter.name === 'bizplace')
      let fromDateFilter = params.filters.find(filter => filter.name === 'fromDate')
      let toDateFilter = params.filters.find(filter => filter.name === 'toDate')
      let routeIdFilter = params.filters.find(filter => filter.name === 'routeId')
      let stopIdFilter = params.filters.find(filter => filter.name === 'stopId')
      let toteIdFilter = params.filters.find(filter => filter.name === 'toteId')

      let orderInfoFilter
      const orderInfoParamIdx = params.filters.findIndex(param => param.name === 'orderInfo')
      if (orderInfoParamIdx >= 0) {
        orderInfoFilter = params.filters[orderInfoParamIdx].value.toLowerCase().split(',').join('|')

        params.filters.splice(orderInfoParamIdx, 1)
      }

      let toteBoxFilter
      const toteBoxParamIdx = params.filters.findIndex(param => param.name === 'toteBox')
      if (toteBoxParamIdx >= 0) {
        toteBoxFilter = params.filters[toteBoxParamIdx].value

        params.filters.splice(toteBoxParamIdx, 1)
      }

      const qb: SelectQueryBuilder<ReleaseGood> = getRepository(ReleaseGood).createQueryBuilder('rg')

      qb.select('bizplace.name', 'bizplaceName')
        .addSelect('rg.name', 'releaseGoodNo')
        .addSelect('rg.attention_to', 'attentionTo')
        .addSelect('rg.route_id', 'routeId')
        .addSelect('rg.stop_id', 'stopId')
        .addSelect('rg.release_date', 'releaseDate')
        .addSelect(
          `CASE WHEN EXISTS( SELECT 1 FROM order_tote_items oti WHERE oi.id = oti.order_inventory_id)
          THEN
                CASE WHEN EXISTS (SELECT 1 FROM product_details pd2 WHERE pd2.packing_type = 'Carton' AND pd2.product_id = pd.product_id) 
                THEN 
                      CASE WHEN FLOOR(oti.qty / (SELECT pd2.packing_size FROM product_details pd2 WHERE pd2.packing_type = 'Carton' AND pd2.product_id = pd.product_id)) = 0 
                      THEN NULL
                      ELSE FLOOR("oti"."qty" / (SELECT pd2.packing_size FROM product_details pd2 WHERE pd2.packing_type = 'Carton' AND pd2.product_id = "pd"."product_id")) 
                      END
                ELSE NULL
                END
          ELSE
                CASE WHEN EXISTS (SELECT 1 FROM product_details pd2 WHERE pd2.packing_type = 'Carton' AND pd2.product_id = pd.product_id) 
                THEN
                      CASE WHEN FLOOR(oi.release_qty / (SELECT pd2.packing_size FROM product_details pd2 WHERE pd2.packing_type = 'Carton' AND pd2.product_id = pd.product_id)) = 0 
                      THEN NULL
                      ELSE FLOOR(oi.release_qty / (SELECT pd2.packing_size FROM product_details pd2 WHERE pd2.packing_type = 'Carton' AND pd2.product_id = pd.product_id)) 
                      END
                ELSE NULL
                END
          END`,
          'totalCarton'
        )
        .addSelect('case when oti.qty is null then oi.release_qty else oti.qty end', 'orderQuantity')
        .addSelect('ot.name', 'tote')
        .addSelect('case when ot.tote_id is null then false else true end', 'toteBox')
        .addSelect('ots.name', 'sealId')
        .innerJoin('worksheets', 'w', 'w.release_good_id = rg.id')
        .innerJoin('order_inventories', 'oi', 'oi.release_good_id = rg.id')
        .innerJoin('bizplaces', 'bizplace', 'bizplace.id = rg.bizplace_id')
        .leftJoin('order_tote_items', 'oti', 'oti.order_inventory_id = oi.id')
        .leftJoin('order_totes', 'ot', 'ot.id = oti.order_tote_id')
        .leftJoin('order_tote_seals', 'ots', 'ots.order_tote_id = ot.id')
        .innerJoin('product_details', 'pd', 'oi.product_detail_id = pd.id')
        .where('bizplace.id = :bizplaceId', { bizplaceId: bizplaceFilter.value })
        .andWhere('rg.release_date <= :toDate', { toDate: toDateFilter.value })
        .andWhere('rg.release_date >= :fromDate', { fromDate: fromDateFilter.value })
        .andWhere('w.type = :type', { type: 'LOADING' })
        .andWhere('rg.domain_id = :domainId', { domainId: domain.id })
        .andWhere('rg.name IS NOT NULL')
        .andWhere('rg.status NOT IN (:...excludedStatuses)', {
          excludedStatuses: ['PENDING_CANCEL', 'CANCELLED', 'PENDING_WORKSHEET', 'READY_TO_PICK']
        })
        .groupBy('bizplace.name')
        .addGroupBy('rg.name')
        .addGroupBy('rg.route_id')
        .addGroupBy('rg.stop_id')
        .addGroupBy('rg.release_date')
        .addGroupBy('case when oti.qty is null then oi.release_qty else oti.qty end')
        .addGroupBy('ot.name')
        .addGroupBy('case when ot.tote_id is null then false else true end')
        .addGroupBy('ots.name')
        .addGroupBy('rg.attention_to')
        .addGroupBy('oi.inventory_id')
        .addGroupBy('w.created_at')
        .addGroupBy('pd.product_id')
        .addGroupBy('oi.release_qty')
        .addGroupBy('oi.id')
        .addGroupBy('oti.qty')

      orderInfoFilter
        ? qb.andWhere(
            '(rg.name ~* :orderInfoFilter or rg.ref_no ~* :orderInfoFilter or rg.ref_no_2 ~* :orderInfoFilter or rg.ref_no_3 ~* :orderInfoFilter)',
            { orderInfoFilter }
          )
        : ''

      toteBoxFilter ? qb.andWhere('ot.tote_id is not null') : ''

      routeIdFilter ? qb.andWhere(`rg.route_id ilike :routeId`, { routeId: routeIdFilter.value }) : ''

      stopIdFilter ? qb.andWhere(`rg.stop_id ilike :stopId`, { stopId: stopIdFilter.value }) : ''

      toteIdFilter ? qb.andWhere(`ot.name ilike :toteId`, { toteId: toteIdFilter.value }) : ''

      qb.orderBy('w.created_at', 'DESC')
      qb.addOrderBy('ots.name', 'ASC')

      console.time('loadingQcReport')
      let items = await qb.getRawMany()
      console.timeEnd('loadingQcReport')

      items = items.reduce((prev, curr, idx) => {
        if (curr.tote) {
          // Find duplicate by releaseGoodNo, tote, and additional fields to ensure proper grouping
          let reducedItemIndex = prev.findIndex(
            itm =>
              itm.releaseGoodNo === curr.releaseGoodNo &&
              itm.tote === curr.tote &&
              itm.bizplaceName === curr.bizplaceName
          )
          if (reducedItemIndex == -1) {
            // Ensure numeric fields are properly typed when adding new item
            prev.push({
              ...curr,
              orderQuantity: Number(curr.orderQuantity) || 0,
              totalCarton: Number(curr.totalCarton) || 0,
              totalSeal: curr.sealId ? 1 : 0
            })
          } else {
            // Aggregate quantities with explicit numeric conversion
            prev[reducedItemIndex].orderQuantity += Number(curr.orderQuantity) || 0
            prev[reducedItemIndex].totalCarton += Number(curr.totalCarton) || 0
            // Concatenate seal IDs only if they're unique and not null
            if (curr.sealId && !prev[reducedItemIndex].sealId.includes(curr.sealId)) {
              prev[reducedItemIndex].sealId = prev[reducedItemIndex].sealId.concat(', ', curr.sealId)
              prev[reducedItemIndex].totalSeal++
            }
          }
          return prev
        } else {
          // Ensure numeric fields are properly typed for items without totes
          prev.push({
            ...curr,
            orderQuantity: Number(curr.orderQuantity) || 0,
            totalCarton: Number(curr.totalCarton) || 0,
            totalSeal: 0
          })
          return prev
        }
      }, [])

      return items
    } catch (error) {
      throw error
    }
  }
}
