import { string } from 'alga-js'
import refreshTokenHelper from "../../utils/refreshTokenHelper"
import errorHandlingHelper from "../../utils/errorHandlingHelper"
import fetchHelper from "../../utils/fetchHelper"
import getReturnLocatorIds from "../../utils/returnLocatorHelper"

// GET /api/plentyone/products?orderSourceId=123&limit=50&offset=0&search=
// Fetches local products for PlentyOne sync
// The PlentyOne variation ID is stored in M_Product.SKU
// Returns qty on hand filtered by the order source's M_Warehouse_ID
const handleFunc = async (event: any, authToken: any = null) => {
  const token = authToken ?? await getTokenHelper(event)
  const query = getQuery(event)
  const orderSourceId = query.orderSourceId as string
  const limit = Number(query.limit) || 50
  const offset = Number(query.offset) || 0
  const search = (query.search as string)?.trim() || ''

  if(!orderSourceId) {
    return { status: 400, message: 'orderSourceId is required' }
  }

  // Load order source to verify it's PlentyOne and get warehouse info
  const os: any = await fetchHelper(event, `models/c_ordersource/${orderSourceId}`, 'GET', token, null)
  if(!os) {
    return { status: 404, message: 'Order Source not found' }
  }
  if(!(os?.Marketplace?.id === '6' || os?.Marketplace?.identifier === 'plentyone')) {
    return { status: 400, message: 'Selected Order Source is not PlentyOne' }
  }

  // Get the local iDempiere warehouse ID from order source
  const localWarehouseId = os?.M_Warehouse_ID?.id
  // Get PlentyOne warehouse ID for sync
  const plentyOneWarehouseId = os?.PlentyOne_Warehouse_ID || 102
  // Get organization ID from order source
  const orgId = os?.AD_Org_ID?.id

  try {
    // Build filter for products - fetch all products for the organization
    // MPN filtering will be done in the frontend
    let filterParts = []

    // Filter by organization
    if(orgId) {
      filterParts.push(`AD_Org_ID eq ${orgId}`)
    }

    if(search) {
      const escapedSearch = search.replace(/'/g, "''")
      filterParts.push(`(contains(mpn,'${escapedSearch}') or contains(Name,'${escapedSearch}') or contains(SKU,'${escapedSearch}'))`)
    }

    const filter = filterParts.length > 0 ? string.urlEncode(filterParts.join(' and ')) : ''
    const select = string.urlEncode('m_product_id,Name,SKU,mpn')

    // Fetch products with SKU (PlentyOne variation ID)
    // Expand M_Storage to get qty on hand per locator
    let url = `models/m_product?$select=${select}&$expand=${string.urlEncode('M_Storage($expand=M_Locator_ID)')}&$top=${limit}&$skip=${offset}&$orderby=${string.urlEncode('Name asc')}`
    if(filter) {
      url += `&$filter=${filter}`
    }
    const res: any = await fetchHelper(
      event,
      url,
      'GET',
      token,
      null
    )

    if(!res?.records) {
      return { status: 200, records: [], _page: { total: 0, limit, offset }, warehouseId: localWarehouseId, plentyOneWarehouseId }
    }

    // Stock sitting on "return" locators (M_LocatorType with all three
    // IsAvailableFor* flags = false) must not be reported as sellable stock.
    const returnLocatorIds = await getReturnLocatorIds(event, token, orgId || null)

    // Process all records - MPN filtering will be done in the frontend
    const records = res.records.map((p: any) => {
      const storages = p?.M_Storage || []
      let qtyOnHand = 0
      let qtyOnHandAll = 0
      let returnQtyOnHand = 0

      if(Array.isArray(storages)) {
        for(const storage of storages) {
          const qty = Number(storage?.QtyOnHand || 0)
          const locator = storage?.M_Locator_ID
          const locatorId = locator?.id ?? locator
          const isReturnLocator =
            locatorId !== undefined && locatorId !== null && returnLocatorIds.has(Number(locatorId))

          // Track everything (including return locators) for the total reference column.
          qtyOnHandAll += qty
          if (isReturnLocator) returnQtyOnHand += qty

          if (isReturnLocator) continue // Never count return-locator stock as sellable.

          // Filter by warehouse if localWarehouseId is set
          if(localWarehouseId) {
            const storageWarehouseId = locator?.M_Warehouse_ID?.id || locator?.m_warehouse_id
            if(String(storageWarehouseId) === String(localWarehouseId)) {
              qtyOnHand += qty
            }
          } else {
            // If no warehouse filter, sum all
            qtyOnHand += qty
          }
        }
      }

      return {
        id: Number(p.m_product_id || p.id),
        name: p.Name || '',
        sku: p.SKU || '',
        mpn: p.mpn || '',
        plentyOneVariationId: p.mpn || null, // MPN is the PlentyOne variation ID
        qtyOnHand, // Filtered by warehouse, excludes return locators
        qtyOnHandAll, // Total across all warehouses (includes return locators) — reference only
        returnQtyOnHand, // Stock on return-only locators (informational)
        plentyOneStock: null // Will be fetched separately from PlentyOne
      }
    })

    return {
      status: 200,
      records,
      _page: {
        total: res['@odata.count'] ?? records.length,
        limit,
        offset
      },
      warehouseId: localWarehouseId,
      warehouseName: os?.M_Warehouse_ID?.identifier || null,
      plentyOneWarehouseId
    }
  } catch (err: any) {
    const data = errorHandlingHelper(err?.data ?? err, err?.data ?? err)
    return { status: Number(data?.status || 500), message: data?.message || 'Failed to fetch products' }
  }
}

export default defineEventHandler(async (event) => {
  try {
    return await handleFunc(event)
  } catch (err: any) {
    try {
      const authToken = await refreshTokenHelper(event)
      return await handleFunc(event, authToken)
    } catch (error: any) {
      const data = errorHandlingHelper(err?.data ?? err, error?.data ?? error)
      if([401, 402, 403, 407].includes(Number(data.status))) {
        //@ts-ignore
        setCookie(event, 'user', null)
      }
      return data
    }
  }
})
