import { Domain } from '@things-factory/shell'
import { v4 as uuidv4 } from 'uuid'
import { EntityManager, In } from 'typeorm'
import { User } from '@things-factory/auth-base'
import { ReleaseGood, OrderInventory, ORDER_INVENTORY_STATUS, OrderNoGenerator } from '@things-factory/sales-base'
import { Worksheet, WorksheetDetail, WORKSHEET_TYPE, WORKSHEET_STATUS } from '@things-factory/worksheet-base'

export const warehouseReturn = {
  //this function is used for zone picking warehouse return
  //in this case, ro status will remain PROCESSING/PARTIAL_PROCESSING
  async warehouseReturn(_: any, { releaseGoodNo, worksheetDetails }, context: any) {
    const { domain, tx, user }: { domain: Domain; tx: EntityManager; user: User } = context.state

    //find release order
    const releaseOrder: ReleaseGood = await tx.getRepository(ReleaseGood).findOne({
      where: { domain, name: releaseGoodNo }
    })

    if (!releaseOrder) {
      throw new Error(`Release good not found`)
    }

    const existingWorksheet: Worksheet = await tx.getRepository(Worksheet).findOne({
      where: { releaseGood: releaseOrder, type: WORKSHEET_TYPE.WAREHOUSE_RETURN }
    })

    if (existingWorksheet) {
      throw new Error('Existing return worksheet exist for this order')
    }

    let orderInventories = worksheetDetails.map(wsd => wsd.relatedOrderInv)

    //find order inventories
    let foundOrderInventories: OrderInventory[] = await tx.getRepository(OrderInventory).find({
      where: { domain, id: In(orderInventories.map(oi => oi.id)) },
      relations: [
        'inventory',
        'domain',
        'bizplace',
        'releaseGood',
        'product',
        'productDetail',
        'binLocation',
        'orderProduct'
      ]
    })

    let completedLoadingWsdIds: string[] = []

    let returnOrderInventories = foundOrderInventories.flatMap(oi => {
      const matchingWorksheetDetail = worksheetDetails.find(wsd => wsd.relatedOrderInv.id === oi.id)
      if (!matchingWorksheetDetail) return [oi]

      if (matchingWorksheetDetail.returnQty < oi.releaseQty) {
        const remainingOI = {
          ...oi,
          id: undefined,
          name: OrderNoGenerator.orderInventory(),
          status: ORDER_INVENTORY_STATUS.RETURNING,
          releaseQty: matchingWorksheetDetail.returnQty,
          releaseUomValue: (oi.releaseUomValue / oi.releaseQty) * matchingWorksheetDetail.returnQty,
          pickedQty: oi.pickedQty - matchingWorksheetDetail.returnQty,
          sortedQty: oi.sortedQty - matchingWorksheetDetail.returnQty,
          updatedAt: new Date(),
          updater: user
        }

        oi.releaseQty = oi.releaseQty - matchingWorksheetDetail.returnQty
        oi.releaseUomValue = oi.releaseUomValue - remainingOI.releaseUomValue
        oi.pickedQty = oi.pickedQty - matchingWorksheetDetail.returnQty
        oi.sortedQty = oi.sortedQty - matchingWorksheetDetail.returnQty
        oi.updatedAt = new Date()
        oi.updater = user

        return [oi, remainingOI]
      } else if (matchingWorksheetDetail.returnQty === oi.releaseQty) {
        oi.status = ORDER_INVENTORY_STATUS.RETURNING
        oi.updatedAt = new Date()
        oi.updater = user
        completedLoadingWsdIds.push(oi.id)
        return [oi]
      }
    })

    //update current loading wsd status to done
    //for returnQty = releaseQty items
    await tx.getRepository(WorksheetDetail).update(
      { targetInventory: In(completedLoadingWsdIds) },
      {
        status: WORKSHEET_STATUS.DONE,
        updater: user,
        updatedAt: new Date()
      }
    )

    await tx.getRepository(OrderInventory).save(returnOrderInventories)

    //generate worksheet
    let returnWorksheet: Worksheet = {
      name: `RETURN-${uuidv4()}`,
      type: WORKSHEET_TYPE.WAREHOUSE_RETURN,
      status: WORKSHEET_STATUS.DEACTIVATED,
      createdAt: new Date(),
      domain: releaseOrder.domainId,
      bizplace: releaseOrder.bizplaceId,
      releaseGood: releaseOrder,
      creator: user
    }

    await tx.getRepository(Worksheet).save(returnWorksheet)

    //generate worksheet detail only for return order inventories
    const returnWorksheetDetails = returnOrderInventories
      .filter(oi => oi.status === ORDER_INVENTORY_STATUS.RETURNING)
      .map(roi => ({
        name: `RETURN-DETAIL-` + uuidv4(),
        type: WORKSHEET_TYPE.WAREHOUSE_RETURN,
        status: WORKSHEET_STATUS.DEACTIVATED,
        createdAt: new Date(),
        domain: domain,
        bizplaceId: releaseOrder.bizplaceId,
        worksheet: returnWorksheet,
        targetInventory: roi,
        creator: user
      }))

    await tx.getRepository(WorksheetDetail).save(returnWorksheetDetails)
  }
}
