import { StockOpnameLocationRes, StockOpnameRequest } from "@/common/types/stockOpname";
import { Prisma, Team } from "@prisma/client";
import { NextRequest, NextResponse } from "next/server";
import { prisma } from "prisma/client";
import _ from "lodash"
import getServerCredential from "@/common/libs/getServerCredential";

type Quantity = {
  [key in keyof typeof Team]: number | null
}

export async function GET(request: NextRequest) {
  const PAGE_SIZE = 30;

  const params = request.nextUrl.searchParams
  const companyId = params.get('companyId')
  const search = params.get('search')
  const page = params.get('page') ?? null
  const show = params.get('show')
  const intPage = page ? parseInt(page) : 1

  if (!companyId) {
    return NextResponse.json({ error: 'Bad Request. Missing companyId' }, { status: 400 })
  }

  const where: Prisma.ProductWhereInput = {
    AND: {
      stockOpnames: { some: {} },
      companyId: parseInt(companyId),
      isDifferent: show ? (show == 'diff' ? true : false) : undefined,
      OR: [
        { name: { mode: 'insensitive', contains: search ?? '' } },
        { itemCode: { mode: 'insensitive', contains: search ?? '' } },
        { barcode: { mode: 'insensitive', contains: search ?? '' } },
        { stockOpnames: { some: { location: { name: { mode: 'insensitive', contains: search ?? '' } } } } },
      ]
    }
  }

  const products = await prisma.product.findMany({
    skip: (intPage - 1) * PAGE_SIZE,
    take: PAGE_SIZE,
    where,
    select: {
      id: true,
      name: true,
      itemCode: true,
      barcode: true,
      onhandQty: true,
      differenceQty: true,
      isDifferent: true
    }
  })

  const productCount = await prisma.product.count({ where })

  const pagination = {
    page: intPage,
    totalPage: Math.ceil(productCount / PAGE_SIZE),
  }

  type ProductWithSum = typeof products[0] & { quantity: Quantity }

  const productsWithSum: ProductWithSum[] = []

  for (const product of products) {
    const quantity = await calculateOpnameQuantity({
      productId: product.id,
      companyId: parseInt(companyId)
    })
    productsWithSum.push({ ...product, quantity })
  }

  return NextResponse.json({
    result: productsWithSum,
    ...pagination
  })
}

const calculateOpnameQuantity = async (
  where: {
    productId: number,
    companyId: number
  }
): Promise<Quantity> => {
  const quantity: Quantity = { COUNT1: null, COUNT2: null, COUNT3: null, VERIFICATION: null }

  for (const team of Object.values(Team)) {
    const opnameQty = await prisma.stockOpname.groupBy({
      by: ['productId', 'team'],
      _sum: { quantity: true },
      where: { team, ...where }
    })
    if (opnameQty.length === 0) continue
    quantity[team] = opnameQty[0]._sum.quantity
  }
  return quantity
}

export async function POST(request: NextRequest) {
  const credential = getServerCredential()

  if (!credential) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })

  const body: StockOpnameRequest = await request.json()

  const { companyId, team } = credential

  const query = {
    locationId: body.location,
    productId: body.product,
    companyId,
    team
  }

  const stockOpname = await prisma.stockOpname.findFirst({
    where: query
  })

  const data = {
    ...query,
    userId: credential.id,
    quantity: body.quantity,
    isDifferent: false
  }

  let newStockOpname = null

  if (!stockOpname) {
    newStockOpname = await prisma.stockOpname.create({ data })
  } else {
    newStockOpname = await prisma.stockOpname.update({
      where: { id: stockOpname.id },
      data
    })
  }

  await computeIsDifferent({ productId: body.product, companyId: companyId })

  return NextResponse.json(newStockOpname)
}

const SELF_HOST = process.env.SELF_HOST as string

const computeIsDifferent = async ({
  companyId,
  productId
}: {
  companyId: number,
  productId: number
}) => {
  const totalQty: { [key in keyof typeof Team]: number | null } = {
    COUNT1: null,
    COUNT2: null,
    COUNT3: null,
    VERIFICATION: null
  }

  const searchParams = new URLSearchParams({
    companyId: companyId.toString(),
    productId: productId.toString()
  })

  const stockOpnamesFetch = await fetch(`${SELF_HOST}/api/stock-opname/location?${searchParams}`)
  const stockOpnames: StockOpnameLocationRes[] = await stockOpnamesFetch.json()

  let isDifferent: boolean = false

  for (const opname of stockOpnames) {
    let { COUNT1, COUNT2, COUNT3, VERIFICATION } = opname

    if (totalQty['COUNT1'] === null && _.isNumber(COUNT1.quantity)) totalQty['COUNT1'] = 0
    if (totalQty['COUNT2'] === null && _.isNumber(COUNT2.quantity)) totalQty['COUNT2'] = 0
    if (totalQty['COUNT3'] === null && _.isNumber(COUNT3.quantity)) totalQty['COUNT3'] = 0
    if (totalQty['VERIFICATION'] === null && _.isNumber(VERIFICATION.quantity)) totalQty['VERIFICATION'] = 0

    if (_.isNumber(totalQty['COUNT1']) && _.isNumber(COUNT1.quantity)) totalQty['COUNT1'] += COUNT1.quantity
    if (_.isNumber(totalQty['COUNT2']) && _.isNumber(COUNT2.quantity)) totalQty['COUNT2'] += COUNT2.quantity
    if (_.isNumber(totalQty['COUNT3']) && _.isNumber(COUNT3.quantity)) totalQty['COUNT3'] += COUNT3.quantity
    if (_.isNumber(totalQty['VERIFICATION']) && _.isNumber(VERIFICATION.quantity)) totalQty['VERIFICATION'] += VERIFICATION.quantity

    if (_.isNumber(COUNT1.quantity) && _.isNumber(COUNT2.quantity) && COUNT1.quantity !== COUNT2.quantity) isDifferent = true
    if (_.isNumber(COUNT1.quantity) && _.isNumber(COUNT3.quantity) && COUNT1.quantity !== COUNT3.quantity) isDifferent = true
    if (_.isNumber(COUNT2.quantity) && _.isNumber(COUNT3.quantity) && COUNT2.quantity !== COUNT3.quantity) isDifferent = true
  }

  const product = await prisma.product.findFirst({ where: { id: productId } })
  if (!product) return

  const onhandQty = product?.onhandQty || 0

  if (!isDifferent) {
    const conditional = {
      wasVerified: typeof totalQty['VERIFICATION'] === 'number',
      anyCountEqWithOnhand: [totalQty['COUNT1'], totalQty['COUNT2'], totalQty['COUNT3']].includes(onhandQty),
      count1EqWithCount2: totalQty['COUNT1'] !== null && totalQty['COUNT2'] !== null && totalQty['COUNT1'] === totalQty['COUNT2'],
      count1EqWithCount3: totalQty['COUNT1'] !== null && totalQty['COUNT3'] !== null && totalQty['COUNT1'] === totalQty['COUNT3'],
      count2EqWithCount3: totalQty['COUNT2'] !== null && totalQty['COUNT3'] !== null && totalQty['COUNT2'] === totalQty['COUNT3']
    }

    isDifferent = !(
      conditional.wasVerified ||
      conditional.anyCountEqWithOnhand ||
      conditional.count1EqWithCount2 ||
      conditional.count1EqWithCount3 ||
      conditional.count2EqWithCount3
    )
  }

  await prisma.product.update({
    where: { id: product.id },
    data: { isDifferent }
  })
}