import refreshTokenHelper from "../../../utils/refreshTokenHelper"
import forceLogoutHelper from "../../../utils/forceLogoutHelper"
import errorHandlingHelper from "../../../utils/errorHandlingHelper"
import fetchHelper from "../../../utils/fetchHelper"

const chunkArray = (arr: any[], size: number) => {
  const chunks: any[] = []
  for(let i = 0; i < arr.length; i += size) {
    chunks.push(arr.slice(i, i + size))
  }
  return chunks
}

const handleFunc = async (event: any, authToken: any = null) => {
  let data: any = {}
  const token = authToken ?? await getTokenHelper(event)
  const query = getQuery(event)
  // Cross-org by default: staff manage BOM productions for all customer orgs the
  // role can read. Pass ?organizationId= to narrow to a single org.
  const orgFilterId = query.organizationId ? Number(query.organizationId) : null

  // 1. All active BOM products (role/tenant scoped by the token)
  const productFilter = `IsBOM eq true and IsActive eq true`
  const productRes: any = await fetchHelper(event, `models/m_product?$filter=${encodeURIComponent(productFilter)}&$top=1000`, 'GET', token, null)
  const bomProducts: any[] = productRes?.records || []
  if(bomProducts.length === 0) {
    return { records: [], status: 200, message: '' }
  }
  const productById: any = {}
  for(const p of bomProducts) {
    productById[p.id] = p
  }

  // 2. Open (reserved) order lines for those products — QtyReserved > 0 only exists
  //    on completed, not-yet-shipped sales order lines, which is exactly the open set.
  const openLines: any[] = []
  for(const chunk of chunkArray(bomProducts.map((p: any) => p.id), 20)) {
    const lineFilter = `(${chunk.map((id: number) => `M_Product_ID eq ${id}`).join(' or ')}) and QtyReserved gt 0 and IsActive eq true`
    const lineRes: any = await fetchHelper(event, `models/c_orderline?$filter=${encodeURIComponent(lineFilter)}&$expand=C_Order_ID&$orderby=${encodeURIComponent('Created desc')}&$top=500`, 'GET', token, null)
    for(const line of (lineRes?.records || [])) {
      const order = line.C_Order_ID
      if(!order) continue
      if(order.IsSOTrx !== true) continue
      if(!['CO', 'IP'].includes(order.DocStatus?.id)) continue
      if(orgFilterId && Number(order.AD_Org_ID?.id) !== orgFilterId) continue
      openLines.push(line)
    }
  }
  if(openLines.length === 0) {
    return { records: [], status: 200, message: '' }
  }

  // 3. Existing productions linked to those order lines (any status, to show progress)
  const productionsByLine: any = {}
  for(const chunk of chunkArray(openLines.map((l: any) => l.id), 20)) {
    const prodFilter = `(${chunk.map((id: number) => `C_OrderLine_ID eq ${id}`).join(' or ')})`
    const prodRes: any = await fetchHelper(event, `models/m_production?$filter=${encodeURIComponent(prodFilter)}&$top=500`, 'GET', token, null)
    for(const prod of (prodRes?.records || [])) {
      const lineId = prod.C_OrderLine_ID?.id
      if(!lineId) continue
      if(!productionsByLine[lineId]) productionsByLine[lineId] = []
      productionsByLine[lineId].push(prod)
    }
  }

  // 4. Build rows with open/missing quantities
  const records = openLines.map((line: any) => {
    const order = line.C_Order_ID
    const product = productById[line.M_Product_ID?.id] || {}
    const qtyOrdered = Number(line.QtyOrdered ?? 0)
    const qtyDelivered = Number(line.QtyDelivered ?? 0)
    const openQty = qtyOrdered - qtyDelivered

    const productions = (productionsByLine[line.id] || [])
      .filter((p: any) => !['VO', 'RE'].includes(p.DocStatus?.id))
      .map((p: any) => ({
        id: p.id,
        documentNo: p.DocumentNo,
        docStatusId: p.DocStatus?.id || '',
        docStatus: p.DocStatus?.identifier || '',
        isCreated: p.IsCreated?.id === 'Y',
        qty: Number(p.ProductionQty ?? 0)
      }))
    const inProductionQty = productions.reduce((sum: number, p: any) => sum + p.qty, 0)

    return {
      orderLineId: line.id,
      lineNo: line.Line,
      orderId: order.id,
      orderDocumentNo: order.DocumentNo,
      orderDocStatusId: order.DocStatus?.id || '',
      dateOrdered: order.DateOrdered,
      datePromised: order.DatePromised,
      partnerId: order.C_BPartner_ID?.id || '',
      partner: order.C_BPartner_ID?.identifier || '',
      warehouseId: order.M_Warehouse_ID?.id || '',
      warehouse: order.M_Warehouse_ID?.identifier || '',
      organizationId: order.AD_Org_ID?.id || '',
      organization: order.AD_Org_ID?.identifier || '',
      productId: line.M_Product_ID?.id || '',
      productValue: product.Value || '',
      productName: product.Name || line.M_Product_ID?.identifier || '',
      qtyOrdered,
      qtyDelivered,
      openQty,
      inProductionQty,
      missingQty: Math.max(0, openQty - inProductionQty),
      productions
    }
  })

  records.sort((a: any, b: any) => String(b.dateOrdered).localeCompare(String(a.dateOrdered)) || b.orderId - a.orderId)

  data = { records, status: 200, message: '' }
  return data
}

export default defineEventHandler(async (event) => {
  let data: any = {}

  try {
    data = await handleFunc(event)
  } catch(err: any) {
    try {
      let authToken: any = await refreshTokenHelper(event)
      data = await handleFunc(event, authToken)
    } catch(error) {
      data = errorHandlingHelper(err?.data ?? err, error?.data ?? error)
      forceLogoutHelper(event, data)
    }
  }

  return data
})
