import { EntityManager } from 'typeorm'

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

import { rawProductsQuery } from '../../../utils'

export const orderVasReport = {
  async orderVasReport(_: any, params: ListParam, context: any) {
    try {
      const { domain, tx }: { domain: Domain, tx: EntityManager } = context.state
      let bizplaceFilter = params.filters.find(data => data.name === 'bizplace')
      let productInfo = params.filters.find(data => data.name === 'productInfo')
      let orderNo = params.filters.find(data => data.name === 'orderNo')
      let fromDate = params.filters.find(data => data.name === 'fromDate')
      let toDate = params.filters.find(data => data.name === 'toDate')
      let vasFilter = params.filters.find(data => data.name === 'vass')

      // if (!bizplaceFilter) {
      //   throw 'Invalid input'
      // }

      // const bizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
      //   id: bizplaceFilter.value
      // })

      // await rawProductsQuery(tx, params, bizplace)

      let extraQueryFilter = ` AND domain_id = '${domain.id}'`
      if (productInfo) {
        extraQueryFilter = `${extraQueryFilter} AND (
            old_product_name ILIKE '%${productInfo.value}%'
            OR sku ILIKE '%${productInfo.value}%'
            OR old_p_description ILIKE '%${productInfo.value}%'
            OR old_p_brand ILIKE '%${productInfo.value}%'
            OR old_p_brand_sku ILIKE '%${productInfo.value}%'
            OR new_product_name ILIKE '%${productInfo.value}%'
            OR new_sku ILIKE '%${productInfo.value}%'
            OR new_p_description ILIKE '%${productInfo.value}%'
            OR new_p_brand ILIKE '%${productInfo.value}%'
            OR new_p_brand_sku ILIKE '%${productInfo.value}%'
            ) `
      }

      if (orderNo) {
        extraQueryFilter = `${extraQueryFilter} AND order_no ILIKE '%${orderNo.value}%' `
      }

      if (fromDate) {
        extraQueryFilter = `${extraQueryFilter} AND executed_at >= '%${fromDate.value}%' `
      }

      if (toDate) {
        extraQueryFilter = `${extraQueryFilter} AND executed_at <= '%${toDate.value}%' `
      }

      if (bizplaceFilter) {
        extraQueryFilter = `${extraQueryFilter} AND bizplace_id = '${bizplaceFilter.value}'`
      }

      if (vasFilter) {
        extraQueryFilter = `${extraQueryFilter} AND vas_id = '${vasFilter.value}'`
      }

      // (SELECT coalesce(SUM(op.release_qty), 0)
      // FROM order_products op
      // WHERE op.release_good_id = rg.id and p.id = op.product_id and pd.id = op.product_detail_id  and op.batch_id = ov.batch_id) as "release_qty",
      // (SELECT coalesce(SUM(ov2.qty), 0)
      // FROM order_vass ov2
      // WHERE ov2.id = ov.id) as  "qty",
      // (SELECT coalesce(SUM(ov3.output_qty), 0)
      // FROM order_vass ov3
      // WHERE ov3.id = ov.id) as  "output_qty"
      await tx.query(`
      CREATE TEMP TABLE temp_vas_order_report ON COMMIT DROP AS (
        SELECT
            *
        FROM
            (
          SELECT
              ov.id AS "order_vas_id",
              ov.name AS "order_vas_name",
              rg.domain_id AS "domain_id",
              b.id AS "bizplace_id",
              b.name AS "company",
              rg.name AS "order_no",
              rg.ref_no AS "ref_no",
              p.sku AS "sku",
              ov.batch_id AS "batch_no",
              ov.packing_type AS "packing_type",
              ov.uom AS "uom",
              v.id AS "vas_id",
              v.name AS "vas_name",
              v.description AS "vas_description",
              ovi.vas_qty AS "vas_qty",
              p2.sku AS "new_sku",
              ov.new_packing_type AS "new_packing_type",
              ov.new_uom AS "new_uom",
              ov.new_uom_value AS "new_uom_value",
              w.ended_at AS "completion_date",
              p.name AS "old_product_name",
              p.description AS "old_p_description",
              p.brand AS "old_p_brand",
              p.brand_sku AS "old_p_brand_sku",
              p2.name AS "new_product_name",
              p2.description AS "new_p_description",
              p2.brand AS "new_p_brand",
              p2.brand_sku AS "new_p_brand_sku",
              ovi.executed_at AS "executed_at",
              ov.created_at AS "created_at",
              (
              SELECT
                  COALESCE(SUM(op.release_qty),
                  0)
              FROM
                  order_products op
              WHERE
                ov.release_good_id = op.release_good_id
                AND ov.product_id = op.product_id
                AND ov.product_detail_id = op.product_detail_id
                AND op.batch_id = ov.batch_id) AS "release_qty",
              COALESCE(SUM(ov.qty),
              0) AS "qty",
              COALESCE(SUM(ov.output_qty),
              0) AS "output_qty",
              ov.remark AS "vas_remark",
              ovi.vas_remark AS "ovi_remark",
              u.name AS "updater_name",
              u.id AS "updater_id",
              ovi.id AS "ovi_id"
            FROM
              order_vas_items ovi
            INNER JOIN order_vass ov ON
              ovi.order_vas_id = ov.id
            INNER JOIN products p ON
              ov.product_id = p.id
            INNER JOIN product_details pd ON
              pd.id = ov.product_detail_id
            LEFT JOIN products p2 ON
              p2.id = ov.new_product_id
            LEFT JOIN product_details pd2 ON
              pd2.id = ov.new_product_detail_id
            INNER JOIN vass v ON
              v.id = ovi.vas_id
            INNER JOIN release_goods rg ON
              ov.release_good_id = rg.id
            INNER JOIN worksheets w ON
              rg.id = w.release_good_id
            INNER JOIN bizplaces b ON
              b.id = rg.bizplace_id
            LEFT JOIN users u ON
              u.id = ovi.updater_id
            WHERE w.type = 'VAS'
              AND ((w.status <> 'CANCELLED'
                AND rg.status NOT IN ('CANCELLED', 'PENDING_CANCEL'))
                OR (ovi.executed_at NOTNULL
                AND rg.status IN ('CANCELLED', 'PENDING_CANCEL')))
            GROUP BY
              ov.id,
              rg.domain_id,
              b.id,
              b.name,
              rg.name,
              rg.ref_no,
              p.sku,
              v.id,
              ovi.vas_qty,
              p2.sku,
              w.ended_at,
              p.name,
              p.description,
              p.brand,
              p.brand_sku,
              p2.name,
              p2.description,
              p2.brand,
              p2.brand_sku,
              ovi.executed_at,
              ov.remark,
              ovi.vas_remark,
              u.name,
              u.id,
              ovi.id
        UNION
            SELECT 
                  ov.id AS "order_vas_id", 
                  null AS "order_vas_name", 
                  rg.domain_id AS "domain_id",
                  b.id AS "bizplace_id",
                  b.name AS "company", 
                  rg.name AS "order_no", 
                  rg.ref_no AS "ref_no", 
                  null AS "sku",
                  ov.batch_id AS "batch_no", 
                  ov.packing_type AS "packing_type", 
                  ov.uom AS "uom", 
                  v.id AS "vas_id", 
                  '[Add On] ' || v.name AS "vas_name",  
                  v.description AS "vas_description", 
                  ovi.vas_qty AS "vas_qty", 
                  null AS "new_sku",
                  ov.new_packing_type AS "new_packing_type", 
                  ov.new_uom AS "new_uom", 
                  ov.new_uom_value AS "new_uom_value", 
                  null AS "completion_date",
                  null AS "old_product_name",
                  null AS "old_p_description", 
                  null AS "old_p_brand",
                  null AS "old_p_brand_sku",
                  null AS "new_product_name",
                  null AS "new_p_description", 
                  null AS "new_p_brand", 
                  null AS "new_p_brand_sku",
                  ovi.executed_at AS "executed_at",
                  ov.created_at AS "created_at",
                  null AS "release_qty",
                  null AS "qty",
                  null AS "output_qty",
                  ov.remark AS "vas_remark",
                  ovi.vas_remark AS "ovi_remark",
                  u.name AS "updater_name",
                  u.id AS "updater_id",
                  ovi.id AS "ovi_id"
                FROM order_vas_items ovi 
                INNER JOIN vass v ON v.id = ovi.vas_id 
                INNER JOIN order_vass ov ON ov.id = ovi.order_vas_id 
                INNER JOIN release_goods rg ON rg.id = ov.release_good_id
                INNER JOIN bizplaces b ON b.id = rg.bizplace_id 
                LEFT JOIN users u ON u.id = ovi.updater_id
                where ov.batch_id isnull  
                AND ov.packing_type isnull
                AND ov.product_id isnull 
                AND ov.product_detail_id isnull
                ) src
          WHERE
            1 = 1
            ${extraQueryFilter}
        )
        `)

      const total: any = await tx.query(`
          SELECT count(*) FROM temp_vas_order_report
        `)

      const result: any = await tx.query(`
          SELECT * FROM temp_vas_order_report
           ORDER BY "order_no" ASC, "created_at" ASC, "order_no", "sku", "batch_no", "order_vas_name"
      `)

      let items = result.map(item => {
        let data = {
          bizplace: {
            name: item.company,
            description: item.bizplace_description
          },
          releaseGood: {
            name: item.order_no,
            refNo: item.ref_no
          },
          orderVas: {
            id: item.order_vas_id,
            name: item.order_vas_name,
            batchId: item.batch_no,
            packingType: item.packing_type,
            uom: item.uom,
            uomValue: item.uom_value,
            newPackingType: item.new_packing_type,
            newUom: item.new_uom,
            newUomValue: item.new_uom_value,
            outputQty: item.output_qty,
            product: { sku: item.sku },
            newProduct: { sku: item.new_sku },
            qty: item.qty,
            remark: item.vas_remark
          },
          orderVasItem: {
            id: item.ovi_id,
            vas: {
              id: item.vas_id,
              name: item.vas_name,
              description: item.vas_description
            },
            vasQty: item.vas_qty,
            executedAt: item.executed_at,
            vasRemark: item.ovi_remark
          },
          orderInventory: {
            releaseQty: item.release_qty
          },
          worksheet: {
            endedAt: item.completion_date
          },
          user: {
            id:item.updater_id,
            name: item.updater_name
          }
        }

        return data
      })

      return {
        items,
        total: total[0].count
      }
    } catch (error) {
      throw error
    }
  }
}

export const vasReport = {
  async vasReport(_: 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')
      let vasFilter = params.filters.find(data => data.name === 'vas')
      let typeFilter = params.filters.find(data => data.name === 'type')
      const domain = context.state.domain

      if (!bizplaceFilter) {
        throw 'Invalid input'
      }

      const bizplace: Bizplace = await tx.getRepository(Bizplace).findOne({
        id: bizplaceFilter.value
      })

      await rawProductsQuery(tx, params, bizplace)

      let extraQueryFilter = ''

      if (vasFilter) {
        extraQueryFilter = `${extraQueryFilter} and (
          vas_name ilike '%${vasFilter.value}%' 
          or vas_description ilike '%${vasFilter.value}%') `
      }

      if (typeFilter) {
        extraQueryFilter = `${extraQueryFilter} and vas_type = '${typeFilter.value}' `
      }

      await tx.query(
        `
          create temp table temp_vas_order_report on commit drop as (
            select * from (
              select v.id as "vas_id",
              v."name" as "vas_name", 
              v.description as "vas_description",
              v.type as "vas_type",
              (SELECT coalesce(SUM(ovi.vas_qty), 0) 
             FROM order_vas_items ovi
             inner join order_vass ov on ov.id = ovi.order_vas_id
             inner join release_goods rg on ov.release_good_id = rg.id
             inner join worksheets w on ov.release_good_id = w.release_good_id
             inner join bizplaces b on rg.bizplace_id = b.id
             WHERE ovi.vas_id  = v.id
             and w.bizplace_id = $1
             and w."type" = 'VAS'
             and ((w.status <> 'CANCELLED'
             and rg.status not in ('CANCELLED', 'PENDING_CANCEL'))
             or (ovi.executed_at notnull and rg.status in ('CANCELLED', 'PENDING_CANCEL')))
             and ovi.executed_at >=  $3 and ovi.executed_at <= $4
             ) as "vas_qty",
             (SELECT max(ovi2.executed_at)
             FROM order_vas_items ovi2
             inner join order_vass ov2 on ov2.id = ovi2.order_vas_id
             WHERE ovi2.vas_id  = v.id
             and ov2.bizplace_id = $1
             ) as "executed_at"
              from vass v
              where v.domain_id = $2
            )src
            where 1=1
            and "vas_qty" > 0
            ${extraQueryFilter}
          )          
          `,
        [bizplace.id, domain.id, fromDate.value, toDate.value]
      )

      const total: any = await tx.query(`
          select count(*) from temp_vas_order_report
        `)

      const result: any = await tx.query(
        `
          select * from temp_vas_order_report
          order by "vas_name", "vas_description"
          `
      )

      let items = result.map(item => {
        let data = {
          bizplace: {
            name: bizplace.name
          },
          orderVasItem: {
            vas: { id: item.vas_id, name: item.vas_name, description: item.vas_description, type: item.vas_type },
            vasQty: item.vas_qty,
            executedAt: item.executed_at
          }
        }

        return data
      })

      return {
        items,
        total: total[0].count
      }
    } catch (error) {
      throw error
    }
  }
}
