import { Bizplace } from '@things-factory/biz-base'
import { ListParam } from '@things-factory/shell'
import { EntityManager, getRepository } from 'typeorm'

export const elcclInventoryHistoryPalletDetailReport = {
  async elcclInventoryHistoryPalletDetailReport(_: any, params: ListParam, context: any) {
    try {
      const { tx }: { tx: EntityManager } = context.state

      let bizplaceFilter = params.filters.find(data => data.name === 'bizplace')

      let fromDate = params.filters.find(data => data.name === 'fromDate')
      let toDate = params.filters.find(data => data.name === 'toDate')

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

      let bizplaceQuery = ''
      if (bizplaceFilter) {
        const bizplace: Bizplace = await getRepository(Bizplace).findOne({
          id: bizplaceFilter.value
        })

        if (bizplace) {
          bizplaceQuery = "AND i2.bizplace_id = '" + bizplace.id + "'"
        } else {
          throw 'Invalid input'
        }
      }

      await tx.query(
        `
        CREATE TEMP TABLE invHistory as (
          select COALESCE(js.name, ar.name, 'NEW') as job_sheet,
          COALESCE(js.container_size, '') as container_size,
          i2.batch_id,
          bzp.name as bizplace_name,
          coalesce(plt.name, i2.pallet_id) as pallet_id, ih.seq, ih.status, ih.transaction_type, i2.product_id, 
          ih.id as inventory_history_id, ih.packing_type, ih.qty, ih.opening_qty,
          ih.uom_value, ih.opening_uom_value, ih.created_at
          from inventories i2 
          inner join reduced_inventory_histories ih on ih.pallet_id = i2.pallet_id and ih.domain_id = $1
          inner join bizplaces bzp on bzp.id = ih.bizplace_id
          left join order_inventories oi on oi.inventory_id = i2.id and oi.arrival_notice_id is not null
          left join arrival_notices ar on ar.id = oi.arrival_notice_id
          left join job_sheets js on js.arrival_notice_ref_no = ar.name
          left join pallets plt on plt.id = i2.reusable_pallet_id
          where i2.domain_id = $1
          ${bizplaceQuery}
          and i2.ref_inventory_id is null
        )`,
        [context.state.domain.id]
      )

      await tx.query(`
        CREATE TEMP TABLE inventoryHistoryMovement AS (
          select bizplace_name, container_size, pallet_id, seq, status, transaction_type, batch_id,
          inventory_history_id, packing_type, qty, opening_qty, uom_value, opening_uom_value, created_at, job_sheet from (
            select row_number() over(partition by job_sheet, pallet_id order by created_at asc) as rn, *  from invHistory where      
            status = 'STORED' and (transaction_type = 'NEW' or transaction_type = 'CANCEL_ORDER' or transaction_type = 'RETURN' or transaction_type = 'PUTAWAY')
          )as invIn where rn = 1
          union all
          select bizplace_name, container_size, pallet_id, seq, status, transaction_type, batch_id,
          inventory_history_id, packing_type, qty, opening_qty, uom_value, opening_uom_value, created_at, job_sheet from (
            select row_number() over(partition by job_sheet, pallet_id order by created_at desc) as rn, *  from invHistory ih1
            where (ih1.status = 'TERMINATED')
          ) as invOut where rn = 1 and invOut.transaction_type <> 'RETURN'
        );
      `)

      const result: any = await tx.query(
        `    
        with inventoryHistoriesByPallet as (
          select invHistory.bizplace_name, invHistory.container_size, invHistory.job_sheet, invHistory.batch_id,
          SUM(case when invHistory.created_at < $1 then 
              case when invHistory.status = 'STORED' then 1 else -1 end
              else 0 end) as opening_balance,
          SUM(case when invHistory.created_at >= $1 
              and invHistory.created_at <= $2 then 
              case when invHistory.status = 'STORED' then 1 else 0 end
              else 0 end) as in_balance,
          SUM(case when invHistory.created_at >= $1 
              and invHistory.created_at <= $2 then 
              case when invHistory.status = 'TERMINATED' then 1 else 0 end
              else 0 end) as out_balance
          from(
            select * from inventoryHistoryMovement
          ) as invHistory group by bizplace_name, container_size, job_sheet, batch_id
        )
        select invh.*, invh.opening_balance + invh.in_balance - invh.out_balance as closing_balance 
        , (
          select json_agg(json_build_object('created_at', created_at, 'in_balance', in_balance, 'out_balance', out_balance)) as jsonData from 
            (
              select bizplace_name, batch_id, job_sheet, created_at::date,
              SUM(case when status = 'STORED' then 1 else 0 end) as in_balance,
              SUM(case when status = 'TERMINATED' then 1 else 0 end) as out_balance
              from inventoryHistoryMovement
              where created_at >= $1 and 
              created_at <= $2 and 
              bizplace_name = invh.bizplace_name and
              batch_id = invh.batch_id and job_sheet = invh.job_sheet
              group by bizplace_name, batch_id, job_sheet, created_at::date
              order by created_at
            ) 
          as t
        )::varchar as json_date_movement
        from inventoryHistoriesByPallet invh
        where (invh.opening_balance > 0
        or invh.in_balance > 0
        or invh.out_balance > 0)
        order by invh.bizplace_name, invh.batch_id;
      `,
        [fromDate.value, toDate.value]
      )

      await tx.query(`drop table inventoryHistoryMovement, invHistory`)

      let items = result.map(item => {
        return {
          bizplace: { name: item.bizplace_name },
          jobSheet: item.job_sheet,
          batchId: item.batch_id,
          openingBalance: item.opening_balance,
          inBalance: item.in_balance,
          outBalance: item.out_balance,
          closingBalance: item.closing_balance,
          jsonDateMovement: item.json_date_movement,
          containerSize: item.container_size
        }
      })

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