import { ReleaseGood, OrderInventory, ORDER_INVENTORY_STATUS, ORDER_STATUS } from '@things-factory/sales-base'
import {
  Worksheet,
  WorksheetDetail,
  WorksheetController,
  WorksheetNoGenerator,
  WORKSHEET_STATUS,
  WORKSHEET_TYPE
} from '@things-factory/worksheet-base'
import { Location } from '@things-factory/warehouse-base'
import { EntityManager, In } from 'typeorm'
import { User } from '@things-factory/auth-base'
import { Domain } from '@things-factory/biz-base'

export const generateWorksheetZonePicking = {
  async generateWorksheetZonePicking(_: any, { releaseGoods }, context: any): Promise<Worksheet[]> {
    const { user, domain, tx }: { user: User; domain: Domain; tx: EntityManager } = context.state

    let worksheets = []
    //fetch all orders
    let relatedReleaseGoods: ReleaseGood[] = await tx.getRepository(ReleaseGood).find({
      where: {
        name: In(releaseGoods),
        status: ORDER_STATUS.PENDING_WORKSHEET,
        domain: domain
      }
    })

    //split by bizplace
    const bizplaces = new Set()
    relatedReleaseGoods.forEach(item => {
      bizplaces.add(item.bizplaceId)
    })

    for (const bizplace of bizplaces) {
      let bizplaceFilteredReleaseGoods = relatedReleaseGoods.filter(rg => rg.bizplaceId === bizplace)

      let releaseGoodIds = bizplaceFilteredReleaseGoods.map(rg => rg.id)

      //fetch all oi
      let orderInventories: OrderInventory[] = await tx.getRepository(OrderInventory).find({
        where: {
          releaseGood: In(releaseGoodIds)
        },
        relations: ['inventory', 'inventory.location']
      })

      let oiIds = orderInventories.map(item => item.id)

      let zones = await tx
        .getRepository(Location)
        .createQueryBuilder('l')
        .select('DISTINCT l.zone', 'zone')
        .innerJoin('inventories', 'iv', 'iv.location_id = l.id')
        .innerJoin('order_inventories', 'oi', 'oi.inventory_id = iv.id')
        .where('oi.id in (:...ids)', { ids: oiIds })
        .getRawMany()
        .then(rows => rows.map(row => row.zone))

      //split by zone
      for (const zone of zones) {
        //generate worksheets by zone
        let zoneFilteredOi = orderInventories.filter(item => item.inventory.location.zone == zone)

        let worksheet: Worksheet = {
          name: WorksheetNoGenerator.generate(WORKSHEET_TYPE.ZONE_PICKING),
          type: WORKSHEET_TYPE.ZONE_PICKING,
          status: WORKSHEET_STATUS.DEACTIVATED,
          bizplace: bizplace,
          domain: domain,
          creator: user,
          updater: user,
          createdAt: new Date(),
          updatedAt: new Date(),
          zone: zone
        }

        worksheet = await tx.getRepository(Worksheet).save(worksheet)

        if (zoneFilteredOi?.length > 0) {
          worksheet.worksheetDetails = []

          for (const oi of zoneFilteredOi) {
            //generate worksheet detail for all OIs in the group
            const worksheetDetail: WorksheetDetail = {
              name: WorksheetNoGenerator.generateDetail(WORKSHEET_TYPE.ZONE_PICKING),
              domain: domain,
              bizplace: bizplace,
              worksheet: worksheet,
              type: WORKSHEET_TYPE.ZONE_PICKING,
              status: WORKSHEET_STATUS.DEACTIVATED,
              targetInventory: oi,
              creator: user,
              updater: user,
              createdAt: new Date(),
              updatedAt: new Date()
            }

            await tx.getRepository(WorksheetDetail).save(worksheetDetail)
            worksheet.worksheetDetails.push({ ...worksheetDetail })
          }

          //update for all OIs
          await tx.getRepository(OrderInventory).update(
            { id: In(zoneFilteredOi.map(oi => oi.id)) },
            {
              refWorksheetId: worksheet.id,
              status: ORDER_INVENTORY_STATUS.READY_TO_PICK,
              updater: user,
              updatedAt: new Date()
            }
          )
        }
        worksheets.push(worksheet)
      }

      await tx.getRepository(ReleaseGood).update(
        { id: In(bizplaceFilteredReleaseGoods.map(rg => rg.id)) },
        {
          status: ORDER_STATUS.READY_TO_PICK,
          updater: user,
          updatedAt: new Date()
        }
      )
      await tx.getRepository(ReleaseGood).update(
        { id: In(bizplaceFilteredReleaseGoods.map(rg => rg.id)) },
        {
          status: ORDER_STATUS.READY_TO_PICK,
          updater: user,
          updatedAt: new Date()
        }
      )
    }
    return worksheets
  }
}
