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

const handleFunc = async (event: any, authToken: any = null) => {
  let data: any = { records: [] }
  const token = authToken ?? await getTokenHelper(event)
  const query = getQuery(event)
  const productId = query.productId

  if (!productId) {
    return { status: 400, message: 'Product ID is required' }
  }

  // Helper to extract ID from value (handles both number and object with id)
  const extractId = (value: any): number | null => {
    if (typeof value === 'number') return value
    if (value?.id) return value.id
    return null
  }

  // Fetch transactions for the product
  const transactionRes: any = await fetchHelper(
    event,
    `models/m_transaction?$filter=${string.urlEncode('M_Product_ID eq ' + productId)}&$orderby=${string.urlEncode('MovementDate desc')}`,
    'GET',
    token,
    null
  )

  if (!transactionRes?.records || transactionRes.records.length === 0) {
    return data
  }

  // Collect unique IDs for batch fetching
  const locatorIds = new Set<number>()
  const inOutLineIds = new Set<number>()

  for (const transaction of transactionRes.records) {
    const locatorId = extractId(transaction.M_Locator_ID)
    const inOutLineId = extractId(transaction.M_InOutLine_ID)
    if (locatorId) locatorIds.add(locatorId)
    if (inOutLineId) inOutLineIds.add(inOutLineId)
  }

  // Fetch product details
  const productRes: any = await fetchHelper(
    event,
    `models/M_Product/${productId}`,
    'GET',
    token,
    null
  )
  const productInfo = {
    name: productRes?.Name || '',
    sku: productRes?.SKU || ''
  }

  // Fetch locator details
  const locatorDetails: Record<number, string> = {}
  if (locatorIds.size > 0) {
    const locatorIdArray = Array.from(locatorIds)
    const filterParts = locatorIdArray.map(id => `M_Locator_ID eq ${id}`).join(' or ')
    try {
      const locatorRes: any = await fetchHelper(
        event,
        `models/M_Locator?$filter=${string.urlEncode(filterParts)}&$select=${string.urlEncode('M_Locator_ID,Value')}`,
        'GET',
        token,
        null
      )
      if (locatorRes?.records) {
        for (const locator of locatorRes.records) {
          locatorDetails[locator.id] = locator.Value || locator.identifier || ''
        }
      }
    } catch (err) {
      console.error('Error fetching locator details:', err)
    }
  }

  // Fetch inout line details to get M_InOut_ID
  const inOutLineDetails: Record<number, number | null> = {}
  const inOutIds = new Set<number>()

  if (inOutLineIds.size > 0) {
    const inOutLineIdArray = Array.from(inOutLineIds)
    const batchSize = 50

    for (let i = 0; i < inOutLineIdArray.length; i += batchSize) {
      const batch = inOutLineIdArray.slice(i, i + batchSize)
      const filterParts = batch.map(id => `M_InOutLine_ID eq ${id}`).join(' or ')
      try {
        const inOutLineRes: any = await fetchHelper(
          event,
          `models/M_InOutLine?$filter=${string.urlEncode(filterParts)}&$select=${string.urlEncode('M_InOutLine_ID,M_InOut_ID')}`,
          'GET',
          token,
          null
        )
        if (inOutLineRes?.records) {
          for (const line of inOutLineRes.records) {
            const inOutId = extractId(line.M_InOut_ID)
            inOutLineDetails[line.id] = inOutId
            if (inOutId) inOutIds.add(inOutId)
          }
        }
      } catch (err) {
        console.error('Error fetching inout line details:', err)
      }
    }
  }

  // Fetch shipment details (M_InOut with C_BPartner and C_Order info)
  const shipmentDetails: Record<number, any> = {}

  if (inOutIds.size > 0) {
    const inOutIdArray = Array.from(inOutIds)
    const batchSize = 50

    for (let i = 0; i < inOutIdArray.length; i += batchSize) {
      const batch = inOutIdArray.slice(i, i + batchSize)
      const filterParts = batch.map(id => `M_InOut_ID eq ${id}`).join(' or ')

      try {
        const shipmentRes: any = await fetchHelper(
          event,
          `models/M_InOut?$filter=${string.urlEncode(filterParts)}&$select=${string.urlEncode('M_InOut_ID,DocumentNo,IsSOTrx,MovementType,C_BPartner_ID,C_Order_ID')}`,
          'GET',
          token,
          null
        )

        if (shipmentRes?.records) {
          // Collect bpartner and order IDs
          const bpartnerIds = new Set<number>()
          const orderIds = new Set<number>()

          for (const shipment of shipmentRes.records) {
            const bpartnerId = extractId(shipment.C_BPartner_ID)
            const orderId = extractId(shipment.C_Order_ID)
            if (bpartnerId) bpartnerIds.add(bpartnerId)
            if (orderId) orderIds.add(orderId)

            shipmentDetails[shipment.id] = {
              documentNo: shipment.DocumentNo || '',
              isSOTrx: shipment.IsSOTrx === true || shipment.IsSOTrx === 'Y',
              movementType: shipment.MovementType || '',
              bpartnerId: bpartnerId,
              orderId: orderId,
              bpartnerName: '',
              externalOrderId: ''
            }
          }

          // Fetch bpartner names
          if (bpartnerIds.size > 0) {
            const bpartnerIdArray = Array.from(bpartnerIds)
            const bpartnerFilter = bpartnerIdArray.map(id => `C_BPartner_ID eq ${id}`).join(' or ')
            try {
              const bpartnerRes: any = await fetchHelper(
                event,
                `models/C_BPartner?$filter=${string.urlEncode(bpartnerFilter)}&$select=${string.urlEncode('C_BPartner_ID,Name')}`,
                'GET',
                token,
                null
              )
              if (bpartnerRes?.records) {
                const bpartnerMap: Record<number, string> = {}
                for (const bp of bpartnerRes.records) {
                  bpartnerMap[bp.id] = bp.Name || ''
                }
                // Update shipment details with bpartner names
                for (const shipmentId in shipmentDetails) {
                  const bpId = shipmentDetails[shipmentId].bpartnerId
                  if (bpId && bpartnerMap[bpId]) {
                    shipmentDetails[shipmentId].bpartnerName = bpartnerMap[bpId]
                  }
                }
              }
            } catch (err) {
              console.error('Error fetching bpartner details:', err)
            }
          }

          // Fetch order external IDs
          if (orderIds.size > 0) {
            const orderIdArray = Array.from(orderIds)
            const orderFilter = orderIdArray.map(id => `C_Order_ID eq ${id}`).join(' or ')
            try {
              const orderRes: any = await fetchHelper(
                event,
                `models/C_Order?$filter=${string.urlEncode(orderFilter)}&$select=${string.urlEncode('C_Order_ID,ExternalOrderId')}`,
                'GET',
                token,
                null
              )
              if (orderRes?.records) {
                const orderMap: Record<number, string> = {}
                for (const order of orderRes.records) {
                  orderMap[order.id] = order.ExternalOrderId || ''
                }
                // Update shipment details with external order IDs
                for (const shipmentId in shipmentDetails) {
                  const ordId = shipmentDetails[shipmentId].orderId
                  if (ordId && orderMap[ordId]) {
                    shipmentDetails[shipmentId].externalOrderId = orderMap[ordId]
                  }
                }
              }
            } catch (err) {
              console.error('Error fetching order details:', err)
            }
          }
        }
      } catch (err) {
        console.error('Error fetching shipment details:', err)
      }
    }
  }

  // Map transaction records with enriched data
  const enrichedRecords = transactionRes.records.map((transaction: any) => {
    const locatorId = extractId(transaction.M_Locator_ID)
    const inOutLineId = extractId(transaction.M_InOutLine_ID)
    const inOutId = inOutLineId ? inOutLineDetails[inOutLineId] : null
    const shipmentInfo = inOutId ? shipmentDetails[inOutId] || {} : {}

    return {
      id: transaction.id || transaction.uid,
      movementDate: transaction.MovementDate || '',
      movementQty: transaction.MovementQty || 0,
      movementType: transaction.MovementType?.identifier || transaction.MovementType || '',
      movementTypeId: transaction.MovementType?.id || '',
      locator: locatorId ? locatorDetails[locatorId] || '' : '',
      locatorId: locatorId,
      productId: extractId(transaction.M_Product_ID),
      productName: productInfo.name,
      productSku: productInfo.sku,
      inOutLineId: inOutLineId,
      inOutId: inOutId,
      bpartnerName: shipmentInfo.bpartnerName || '',
      bpartnerId: shipmentInfo.bpartnerId || null,
      externalOrderId: shipmentInfo.externalOrderId || '',
      orderId: shipmentInfo.orderId || null,
      shipmentDocumentNo: shipmentInfo.documentNo || '',
      isSOTrx: shipmentInfo.isSOTrx || false,
      shipmentMovementType: shipmentInfo.movementType || ''
    }
  })

  data.records = enrichedRecords
  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: any) {
      data = errorHandlingHelper(err?.data ?? err, error?.data ?? error)
      forceLogoutHelper(event, data)
    }
  }

  return data
})
