import { EntityManager } from 'typeorm'
import { User } from '@things-factory/auth-base'
import { Bizplace } from '@things-factory/biz-base'
import { ListParam } from '@things-factory/shell'
import { rawProductsQuery } from '../../../utils'

export const inboundOrderDetailsReport = {
  async inboundOrderDetailsReport(_: any, params: ListParam, context: any) {
    try {
      const { tx }: { tx: EntityManager } = context.state
      let bizplaceFilter = { name: '', operator: '', value: '' }
      let userFilter = params.filters.find(data => data.name === 'user')
      let fromDate = params.filters.find(data => data.name === 'fromDate')
      let toDate = params.filters.find(data => data.name === 'toDate')
      let ganNo = params.filters.find(data => data.name === 'ganNo')
      let grnNo = params.filters.find(data => data.name === 'grnNo')
      let poNo = params.filters.find(data => data.name === 'poNo')
      let doNo = params.filters.find(data => data.name === 'doNo')
      let cartonId = params.filters.find(data => data.name === 'cartonId')
      let lotId = params.filters.find(data => data.name == 'palletId')
      let byUnloadComplete = params.filters.find(data => data.name == 'byUnloadComplete')

      if (userFilter) {
        const user: User = await tx.getRepository(User).findOne({
          where: { id: userFilter.value },
          relations: ['bizplaces']
        })

        const bizplace: Bizplace = user.bizplaces[0]

        if (!bizplace) throw 'Invalid input'

        bizplaceFilter = { name: 'bizplace', operator: 'eq', value: bizplace.id }
      } else {
        bizplaceFilter = params.filters.find(data => data.name === 'bizplace')
      }

      if (!bizplaceFilter || !fromDate || !toDate) throw 'Invalid input'

      const bizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
        id: bizplaceFilter.value
      })

      await rawProductsQuery(tx, params, bizplace)

      let extraQueryFilters = ''
      if (ganNo) {
        extraQueryFilters = `${extraQueryFilters} and gan_no like '%${ganNo.value}%' `
      }
      if (grnNo) {
        extraQueryFilters = `${extraQueryFilters} and grn_no like '%${grnNo.value}%' `
      }
      if (poNo) {
        extraQueryFilters = `${extraQueryFilters} and purchase_order_name like '%${poNo.value}%' `
      }
      if (doNo) {
        extraQueryFilters = `${extraQueryFilters} and delivery_order_no like '%${doNo.value}%' `
      }
      if (lotId) {
        extraQueryFilters = `${extraQueryFilters} and pallet_id like '%${lotId.value}%' `
      }
      if (cartonId) {
        extraQueryFilters = `${extraQueryFilters} and carton_id like '%${cartonId.value}%' `
      }

      await tx.query(
        `
        create temp table temp_inbound_order_report on commit drop as (
          select src2.*,
          w.started_at as "unload_start", w.ended_at as "unload_complete",
          w2.started_at as "putaway_start", w2.ended_at as "putaway_complete",
          cp.id as "supplier_id", cp.company_name as "supplier_name",
          u.name as "accepted_by", u2.name as "unloaded_by", u3.name as "putaway_by"
	        from (
		        select * from ( 
              select an.id, an.accepted_by_id, an.name as "gan_no", an.ref_no as "ref_no_1", an.ref_no_2 as "ref_no_2", an.ref_no_3 as "ref_no_3",  
              an.loose_item, an.import_cargo, an.container_no, an.container_size, an.own_transport, 
              an.accepted_at, u1.name as "order_created_by", an.created_at as "order_created_at", an.delivery_order_no, 
              b2.id as "bizplace_id", b2.name as "bizplace_name", b2.description as "bizplace_description",
              grn.name as "grn_no",		
              po.id as "purchase_order_id", po.name as "purchase_order_name", po.supplier_id as "po_supplier_id", 
              row_number() over(partition by an.name order by an.name, p.sku, oi.batch_id) as "order_line_item",
              p.id as "product_id", p.sku as "product_sku", p.name as "product_name", p.description as "product_description", p.type as "product_type",
              oi.packing_size as "pack_size", oi.packing_type as "pack_type", oi.actual_pack_qty, oi.actual_pack_uom_value, oi.uom, oi.batch_id, oi.batch_id_ref,
              oi.unloaded_at as "unloaded_at", oi.putaway_at as "putaway_at", oi.unloaded_by_id as "oi_unloaded_by_id", oi.putaway_by_id as "oi_putaway_by_id",
              i.pallet_id, i.carton_id, i.expiration_date, i.condition_of_goods, i.manufacture_date, i.unit_cost,
              pd.volume as "unit_volume", pd.nett_weight as "unit_nett_weight", pd.gross_weight as "unit_gross_weight", pd.weight_unit as "weight_unit"
			        from (
			          select * from arrival_notices 
                where domain_id = $1 and bizplace_id = $2 and status ='DONE'
                ${!byUnloadComplete.value ? `and created_at >= $3 and created_at <= $4` : ``}
              ) an
              left join users u1 on u1.id = an.creator_id
              left join purchase_orders po on po.id = an.purchase_order_id
			        left join goods_receival_notes grn on grn.arrival_notice_id = an.id		      
              inner join order_inventories oi on oi.arrival_notice_id = an.id
              inner join bizplaces b2 on b2.id = an.bizplace_id
              inner join inventories i on i.id = oi.inventory_id
              inner join temp_products p on p.id = oi.product_id 
              inner join product_details pd on pd.id = oi.product_detail_id
              inner join (
                select 
                  distinct on (
                    arrival_notice_id, product_detail_id,
                    batch_id
                  ) arrival_notice_id, product_detail_id,
                    batch_id
                from 
                  order_products
                where 
                  actual_pack_qty is not null
                  and domain_id = $1
                  and bizplace_id = $2
                order by 
                  arrival_notice_id,
                  product_detail_id,
                  batch_id,
                  created_at
                ) op on op.arrival_notice_id = an.id
                and op.product_detail_id = oi.product_detail_id
                and op.batch_id = oi.batch_id	   
            ) src
            where 1=1
            ${extraQueryFilters}
        ) src2 
        left join contact_points cp on cp.id = src2.po_supplier_id  
        left join users u on u.id = src2.accepted_by_id
        left join users u2 on u2.id = src2.oi_unloaded_by_id 
        left join users u3 on u3.id = src2.oi_putaway_by_id 	
        left join worksheets w on w.arrival_notice_id = src2.id and w."type" ='UNLOADING'
        left join worksheets w2 on w2.arrival_notice_id = src2.id and w2."type" ='PUTAWAY'	
        ${
          byUnloadComplete.value
            ? `where w.ended_at >= $3 and w.ended_at <= $4 and w."type" ='UNLOADING' ORDER BY w.ended_at DESC`
            : `ORDER BY order_created_at DESC`
        }
        )
      `,
        [context.state.domain.id, bizplace.id, fromDate.value, toDate.value]
      )

      const total: any = await tx.query(`
        select count(*) from temp_inbound_order_report
      `)

      const result: any = await tx.query(
        `
        select src2.*,  
        round((src2.actual_pack_qty * src2.unit_volume)::numeric ,4) as total_volume, 
        round((src2.actual_pack_qty * src2.unit_nett_weight)::numeric ,4) as total_unit_nett_weight, 
        round((src2.actual_pack_qty * src2.unit_gross_weight)::numeric ,4) as total_unit_gross_weight
        from temp_inbound_order_report src2
        offset $1 limit $2
      `,
        [(params.pagination.page - 1) * params.pagination.limit, params.pagination.limit]
      )

      let items = result.map(itm => {
        let data = {
          bizplace: {
            description: itm.bizplace_description,
            name: itm.bizplace_name
          },
          grnNo: itm.grn_no,
          ganNo: itm.gan_no,
          deliveryOrderNo: itm.delivery_order_no,
          refNo1: itm.ref_no_1,
          refNo2: itm.ref_no_2,
          refNo3: itm.ref_no_3,
          looseItem: itm.loose_item,
          importCargo: itm.import_cargo,
          containerNo: itm.container_no,
          containerSize: itm.container_size,
          ownTransport: itm.own_transport,
          acceptedBy: itm.accepted_by,
          acceptedAt: itm.accepted_at,
          orderCreatedBy: itm.order_created_by,
          orderCreatedAt: itm.order_created_at,
          unloadStart: itm.unload_start,
          unloadComplete: itm.unload_complete,
          putawayStart: itm.putaway_start,
          putawayComplete: itm.putaway_complete,
          orderLineItem: itm.order_line_item,
          product: {
            id: itm.product_id,
            sku: itm.product_sku,
            name: itm.product_name,
            description: itm.product_description,
            type: itm.product_type
          },
          purchaseOrderId: itm.purchase_order_id,
          purchaseOrderNo: itm.purchase_order_name,
          packType: itm.pack_type,
          packSize: itm.pack_size,
          actualPackQty: itm.actual_pack_qty,
          actualPackUomValue: itm.actual_pack_uom_value,
          uom: itm.uom,
          unitVolume: itm.unit_volume,
          unitCost: itm.unit_cost,
          totalVolume: itm.total_volume,
          unitNettWeight: itm.unit_nett_weight,
          totalUnitNettWeight: itm.total_unit_nett_weight,
          unitGrossWeight: itm.unit_gross_weight,
          totalUnitGrossWeight: itm.total_unit_gross_weight,
          weightUnit: itm.weight_unit,
          palletId: itm.pallet_id,
          cartonId: itm.carton_id,
          batchId: itm.batch_id,
          batchIdRef: itm.batch_id_ref,
          expirationDate: itm.expiration_date,
          conditionOfGoods: itm.condition_of_goods,
          manufactureDate: itm.manufacture_date,
          unloadedAt: itm.unloaded_at,
          unloadedBy: itm.unloaded_by,
          putawayAt: itm.putaway_at,
          putawayBy: itm.putaway_by
        }

        if (itm.supplier_id) {
          data['supplier'] = {
            id: itm.supplier_id,
            name: itm.supplier_name
          }
        }

        return data
      })

      return {
        items,
        total: total[0].count
      }
    } catch (error) {
      throw error
    }
  }
}
