import { EntityManager, In, getConnection } from 'typeorm'

import { User } from '@things-factory/auth-base'
import { Domain } from '@things-factory/shell'
import { ReleaseGood, ORDER_STATUS } from '@things-factory/sales-base'
import { Worksheet, WORKSHEET_STATUS, WORKSHEET_TYPE } from '@things-factory/worksheet-base'
import { loadingWorksheetv2 } from './loading-worksheet-v2'

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

    if (process.env.NODE_ENV == 'development') {
      console.time('getLoadingTask')
    }
    try {
      // 1. Find assigned worksheet
      let worksheet: Worksheet = await tx
        .getRepository(Worksheet)
        .createQueryBuilder('ws')
        .innerJoinAndSelect('ws.bizplace', 'biz')
        .innerJoinAndSelect('ws.releaseGood', 'rg')
        .innerJoin('ws.worksheetDetails', 'wsd')
        .where({
          domain,
          type: WORKSHEET_TYPE.LOADING,
          sorter: user,
          status: In([WORKSHEET_STATUS.EXECUTING, WORKSHEET_STATUS.DEACTIVATED])
        })
        .andWhere('rg.status IN (:...status)', {
          status: [ORDER_STATUS.LOADING, ORDER_STATUS.PROCESSING, ORDER_STATUS.PARTIAL_PROCESSING]
        })
        .andWhere('wsd.status NOT IN (:...status)', { status: [WORKSHEET_STATUS.DONE, WORKSHEET_STATUS.DEACTIVATED] })
        .getOne()

      // 2. If no assigned worksheet, find and assign next available one
      if (!worksheet) {
        let updatedWorksheets = await getConnection().transaction(async (tx2: EntityManager) => {
          let x = await tx2.query(
            `
            UPDATE worksheets ws SET 
              sorter_id = $2,
              updated_at = NOW(),
              updater_id = $2
            FROM (
              SELECT ws.id 
              FROM worksheets ws
              INNER JOIN release_goods rg ON rg.id = ws.release_good_id
              INNER JOIN worksheet_details wsd ON wsd.worksheet_id = ws.id
              WHERE ws.domain_id = $1 
                AND ws.type = 'LOADING'
                AND ws.status IN ('EXECUTING', 'DEACTIVATED')
                AND ws.sorter_id IS NULL
                AND rg.status IN ('LOADING', 'PROCESSING', 'PARTIAL_PROCESSING')
                AND wsd.status NOT IN ('DONE', 'DEACTIVATED')
                AND (rg.sorted_by_id = $2 OR rg.sorted_by_id IS NULL)
              ORDER BY rg.created_at 
              LIMIT 1
            ) src 
            WHERE src.id = ws.id
            RETURNING ws.id
          `,
            [domain.id, user.id]
          )

          return x[0]
        })

        if (updatedWorksheets.length == 0) throw new Error('no suitable worksheet found')

        //fetch updated ws
        worksheet = await tx
          .getRepository(Worksheet)
          .createQueryBuilder('ws')
          .innerJoinAndSelect('ws.releaseGood', 'rg')
          .where('ws.id = :id', { id: updatedWorksheets[0].id })
          .andWhere('ws.sorter_id = :sorter', { sorter: user.id })
          .getOne()
      }

      //validate worksheet is assigned to user
      if (!worksheet) throw new Error('Please try again by clicking the "Get Task" button')

      if (worksheet.status == WORKSHEET_STATUS.DEACTIVATED) {
        await tx.getRepository(Worksheet).update(worksheet.id, {
          status: WORKSHEET_STATUS.EXECUTING,
          startedAt: new Date()
        })
      }

      //update ro sorter if its null
      if (worksheet?.releaseGood.sortedBy == null) {
        await tx.getRepository(ReleaseGood).update(worksheet.releaseGood.id, {
          sortedBy: user
        })
      }

      return loadingWorksheetv2.loadingWorksheetv2(_, { orderNo: worksheet.releaseGood.name, filter: 'all' }, context)
    } catch (error) {
      console.error(error)
      throw error
    } finally {
      if (process.env.NODE_ENV == 'development') {
        console.timeEnd('getLoadingTask')
      }
    }
  }
}
