/**
 * POST /api/orders/stock-lines   body: { orgId, priceListId?, warehouseId? }
 *
 * Every active article of the organization that has stock (QtyOnHand > 0 summed over all locators),
 * with its price from the given price list (newest version) — the "Alle Artikel mit Bestand" action
 * of the order line table (a merchant leaving us: one order with everything in stock, qty = on hand).
 * `warehouseId` restricts the stock to one warehouse's locators (omitted = every warehouse).
 * Return locators (non-shippable) are reported separately (`returnQtyOnHand`) but included in `qtyOnHand`.
 *
 * -> { status, lines: [{ productId, name, value, sku, ean, uom, uomId, qtyOnHand, returnQtyOnHand, priceList, priceStd, hasPrice, isBom }] }
 */
import { string } from 'alga-js'
import fetchHelper from '../../utils/fetchHelper'
import getTokenHelper from '../../utils/getTokenHelper'
import refreshTokenHelper from '../../utils/refreshTokenHelper'
import errorHandlingHelper from '../../utils/errorHandlingHelper'
import { fetchProductsWithStorage } from '../../utils/productStorageHelper'
import getReturnLocatorIds from '../../utils/returnLocatorHelper'

const num = (v: any) => (typeof v === 'number' ? v : parseFloat(v) || 0)
const flag = (v: any) => v === true || v === 'Y'

const handleFunc = async (event: any, body: any, authToken: string | null = null) => {
  const token = authToken ?? await getTokenHelper(event)
  const orgId = Number(body?.orgId)
  if (!orgId) return { status: 400, message: 'orgId missing', lines: [] }
  const priceListId = Number(body?.priceListId) || 0
  const warehouseId = Number(body?.warehouseId) || 0

  // 1) products of the org + their storage rows (paged join in productStorageHelper, no child $expand)
  const productUrl = `models/m_product?$select=${string.urlEncode('M_Product_ID,Name,Value,SKU,UPC,IsBOM,isJtlBom,isEnabledBom,C_UOM_ID')}&$expand=${string.urlEncode('C_UOM_ID($select=Name)')}&$filter=${string.urlEncode(`AD_Org_ID eq ${orgId} and IsActive eq true`)}&$orderby=${string.urlEncode('Name asc')}&$top=5000`
  const [res, returnLocatorIds] = await Promise.all([
    fetchProductsWithStorage(event, token, productUrl),
    getReturnLocatorIds(event, token, null).catch(() => new Set<number>())
  ])

  const stocked: any[] = []
  for (const p of (res?.records || [])) {
    let qtyOnHand = 0, returnQtyOnHand = 0
    for (const s of (p?.M_Storage || [])) {
      if (warehouseId) {
        const wh = Number(s?.M_Locator_ID?.M_Warehouse_ID?.id ?? s?.M_Warehouse_ID?.id ?? s?.M_Warehouse_ID)
        if (Number.isFinite(wh) && wh > 0 && wh !== warehouseId) continue
      }
      const q = num(s?.QtyOnHand)
      qtyOnHand += q
      const loc = Number(s?.M_Locator_ID?.id ?? s?.M_Locator_ID)
      if (Number.isFinite(loc) && returnLocatorIds.has(loc)) returnQtyOnHand += q
    }
    if (qtyOnHand <= 0) continue
    stocked.push({
      productId: Number(p.id || p.M_Product_ID),
      name: p.Name || '',
      value: p.Value || '',
      sku: p.SKU || '',
      ean: p.UPC || '',
      uom: p?.C_UOM_ID?.Name || p?.C_UOM_ID?.identifier || 'Each',
      uomId: p?.C_UOM_ID?.id || 100,
      qtyOnHand: Math.round(qtyOnHand * 1000) / 1000,
      returnQtyOnHand: Math.round(returnQtyOnHand * 1000) / 1000,
      priceList: 0,
      priceStd: 0,
      hasPrice: false,
      isBom: flag(p.IsBOM) || (flag(p.isJtlBom) && !flag(p.isEnabledBom))
    })
  }

  // 2) prices from the newest version of the price list (chunked `or` filters, no child $expand)
  if (priceListId && stocked.length) {
    const ver: any = await fetchHelper(event, `models/m_pricelist_version?$filter=${string.urlEncode(`M_PriceList_ID eq ${priceListId}`)}&$orderby=${string.urlEncode('M_PriceList_Version_ID desc')}&$top=1`, 'GET', token, null)
    const versionId = Number(ver?.records?.[0]?.id) || 0
    if (versionId) {
      const byId = new Map(stocked.map((l) => [l.productId, l]))
      const ids = stocked.map((l) => l.productId)
      for (let i = 0; i < ids.length; i += 60) {
        const chunk = ids.slice(i, i + 60)
        const f = `M_PriceList_Version_ID eq ${versionId} and (${chunk.map((id) => `M_Product_ID eq ${id}`).join(' or ')})`
        const pr: any = await fetchHelper(event, `models/m_productprice?$select=${string.urlEncode('M_Product_ID,PriceList,PriceStd')}&$filter=${string.urlEncode(f)}&$top=500`, 'GET', token, null)
        for (const row of (pr?.records || [])) {
          const l = byId.get(Number(row?.M_Product_ID?.id ?? row?.M_Product_ID))
          if (!l) continue
          l.priceList = num(row.PriceList); l.priceStd = num(row.PriceStd); l.hasPrice = true
        }
      }
    }
  }

  return { status: 200, lines: stocked, orgId, priceListId, warehouseId }
}

export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  let data: any = {}
  try {
    data = await handleFunc(event, body)
  } catch (err: any) {
    try {
      const authToken = await refreshTokenHelper(event)
      data = await handleFunc(event, body, authToken)
    } catch (error: any) {
      data = errorHandlingHelper(err?.data ?? err, error?.data ?? error)
    }
  }
  return data
})
