import { WebhookEventsEnum, webhookHandler } from '@things-factory/integration-base'
import { OrderInventory, ReleaseGood, ORDER_STATUS, ORDER_INVENTORY_STATUS } from '@things-factory/sales-base'
import { INVENTORY_TRANSACTION_TYPE } from '@things-factory/warehouse-base'
import { Inventory,InventoryChange, approveInventoryChanges, INVENTORY_STATUS } from '@things-factory/warehouse-base'
import { Worksheet, WorksheetDetail, WORKSHEET_STATUS, WORKSHEET_TYPE } from '@things-factory/worksheet-base'
import { EntityManager, In, Not } from 'typeorm'

export const warehouseInventoryAdjustment = {
  async warehouseInventoryAdjustment(_: any, { patches }, context: any) {
    try {
      const item = await approveInventoryChanges(patches, context)

      // Retrieve order inventory
      const { tx }: { tx: EntityManager } = context.state

      const _inventoryChanges: any = await tx.getRepository(InventoryChange).find({
        where: { id: In(patches.map(item => item.id)) },
        relations: [
          'inventory',
          'inventory.bizplace',
          'inventory.bizplace.domain',
          'inventory.product',
          'inventory.location',
          'inventory.warehouse',
          'bizplace',
          'bizplace.domain',
          'bizplace.company',
          'bizplace.company.domain',
          'product',
          'product.productDetails',
          'product.productDetails.childProductDetail',
          'location'
        ],
        order: {
          createdAt: 'ASC'
        }
      })

      if (_inventoryChanges.length > 0) {
        if (_inventoryChanges.some(ic => ic.transactionType == INVENTORY_TRANSACTION_TYPE.MISSING)) {
          //handle missing inventory
          const invId: any[] = _inventoryChanges
            .filter((ic: any) => ic.transactionType == INVENTORY_TRANSACTION_TYPE.MISSING)
            .map((ic: any) => ic.inventory.id)

          const orderInventory: OrderInventory[] = await tx.getRepository(OrderInventory).find({
            where: { inventory: In(invId), status: In([ORDER_INVENTORY_STATUS.PICKING, ORDER_INVENTORY_STATUS.PROCESSING]) }
          })

          await tx.getRepository(OrderInventory).update(
            {
              inventory: In(invId),
              status: In([ORDER_INVENTORY_STATUS.PICKING, ORDER_INVENTORY_STATUS.PROCESSING])
            },
            { status: ORDER_INVENTORY_STATUS.MISSING }
          )

          const orderInvId: any[] = orderInventory.map((oi: any) => oi.id)
          const releaseGoodId: any[] = orderInventory.map((roId: any) => roId.releaseGoodId)

          await tx.getRepository(WorksheetDetail).update(
            {
              targetInventory: In(orderInvId),
              status: In([WORKSHEET_STATUS.EXECUTING, WORKSHEET_STATUS.DEACTIVATED])
            },
            { status: WORKSHEET_STATUS.MISSING }
          )

          await tx.getRepository(Worksheet).update(
            {
              releaseGood: In(releaseGoodId),
              status: WORKSHEET_STATUS.EXECUTING,
              type: Not(In([WORKSHEET_TYPE.ZONE_PICKING, WORKSHEET_TYPE.LOADING]))
            },
            { status: WORKSHEET_STATUS.DEACTIVATED }
          )
        } 
        
        if (_inventoryChanges.some(ic => ic.transactionType == INVENTORY_TRANSACTION_TYPE.EXPIRED)) {
          //handle expired inventory
          const invId: any[] = _inventoryChanges
            .filter((ic: any) => ic.transactionType == INVENTORY_TRANSACTION_TYPE.EXPIRED)
            .map((ic: any) => ic.inventory.id)

          const orderInventory: OrderInventory[] = await tx.getRepository(OrderInventory).find({
            where: { inventory: In(invId), status: In([ORDER_INVENTORY_STATUS.PICKING, ORDER_INVENTORY_STATUS.PROCESSING]) }
          })

          const inventoryId: any[] = orderInventory.map((oi: any) => oi.inventoryId)
          const releaseGoodId: any[] = orderInventory.map((roId: any) => roId.releaseGoodId)

          await tx.getRepository(ReleaseGood).update(
            {
              id: In(releaseGoodId),
              status: In([ORDER_STATUS.PROCESSING, ORDER_STATUS.PARTIAL_PROCESSING])
            },
            { status: ORDER_STATUS.OBSOLETE }
          )

          await tx.getRepository(Inventory).update(
            {
              id: In(inventoryId),
              status: INVENTORY_STATUS.STORED
            },
            { obsolete: true }
          )

          await tx.getRepository(InventoryChange).update(
            {
              inventory: In(inventoryId),
              status: 'PENDING'
            },
            { status: 'APPROVED' }
          )
        }

        for (const invChange of _inventoryChanges) {
          webhookHandler(invChange, invChange.inventory.bizplace, WebhookEventsEnum.InventoryAdjusted)
        }
      }
      return item
    } catch (error) {
      throw error
    }
  }
}
