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

const handleFunc = async (event: any, authToken: any = null) => {
  let data: any = {}
  const config = useRuntimeConfig()
  const token = authToken ?? await getTokenHelper(event)
  const organizationId = getCookie(event, 'organizationId')

  // Fetch invoices with related order information
  const res: any = await event.context.fetch(`models/c_invoice?$filter=${string.urlEncode("(isSOTrx eq true OR C_DocTypeTarget_ID eq 1000006) AND (DocStatus eq 'CO' OR DocStatus eq 'CL' OR DocStatus eq 'DR')")}&$select=C_Invoice_ID,C_Invoice_UU,IsActive,DocumentNo,Description,IsApproved,IsPaid,IsPrinted,IsTransferred,Created,DateOrdered,DateInvoiced,DateAcct,TotalLines,GrandTotal,ChargeAmt,Processed,IsSOTrx,IsDiscountPrinted,IsTaxIncluded,SendEMail,IsSelfService,ProcessedOn,IsPayScheduleValid,IsInDispute,IsFixedAssetInvoice,IsOverrideCurrencyRate,DocStatus,C_DocType_ID,C_DocTypeTarget_ID,DocBaseType,SalesRep_ID,AD_User_ID,C_PaymentTerm_ID,C_Currency_ID,PaymentRule,M_PriceList_ID,C_BPartner_ID,C_BPartner_Location_ID,AD_Org_ID,AD_Client_ID,C_Order_ID,C_Payment_ID,isUploadToPayJoe,UploadDatePayJoe,isUploadToLexoffice,UploadDateLexoffice,isUploadToAmazon,UploadDateAmazon&$expand=C_Order_ID($select=Report_Strapi_Reference,C_OrderSource_ID,ExternalOrderId,Created,DateOrdered),C_Payment_ID($select=PayAmt),C_PaymentTerm_ID($select=NetDays)&$orderby=${string.urlEncode('c_invoice_id desc')}`, 'GET', token, null)

  // Fetch allocation lines to get total paid amount for each invoice
  if (res?.records?.length > 0) {
    const invoiceIds = res.records.map((inv: any) => inv.id)

    // Fetch all allocation lines for these invoices (include C_Payment_ID for payment date lookup)
    try {
      const allocRes: any = await event.context.fetch(`models/c_allocationline?$filter=${string.urlEncode(`C_Invoice_ID in (${invoiceIds.join(',')})`)}&$select=C_Invoice_ID,Amount,C_Payment_ID&$expand=C_Payment_ID($select=DocStatus,DateTrx)`, 'GET', token, null)

      if (allocRes?.records?.length > 0) {
        // Sum up allocations per invoice and collect payment IDs
        // Only count allocations where the related payment is completed (CO)
        const allocationSums: Record<number, number> = {}
        const invoicePaymentIds: Record<number, Set<number>> = {}
        for (const alloc of allocRes.records) {
          const invoiceId = alloc.C_Invoice_ID?.id
          const paymentDocStatus = alloc.C_Payment_ID?.DocStatus?.id || alloc.C_Payment_ID?.DocStatus || ''
          if (invoiceId && paymentDocStatus === 'CO') {
            allocationSums[invoiceId] = (allocationSums[invoiceId] || 0) + (alloc.Amount || 0)

            const paymentId = alloc.C_Payment_ID?.id
            if (paymentId) {
              if (!invoicePaymentIds[invoiceId]) invoicePaymentIds[invoiceId] = new Set()
              invoicePaymentIds[invoiceId].add(paymentId)
            }
          }
        }

        // Fetch payment dates
        const allPaymentIds = new Set<number>()
        Object.values(invoicePaymentIds).forEach(payIds => {
          payIds.forEach(id => allPaymentIds.add(id))
        })

        const paymentDates: Record<number, string> = {}
        if (allPaymentIds.size > 0) {
          const paymentIdArray = Array.from(allPaymentIds)
          const batchSize = 50
          for (let i = 0; i < paymentIdArray.length; i += batchSize) {
            const batch = paymentIdArray.slice(i, i + batchSize)
            try {
              const payRes: any = await event.context.fetch(`models/c_payment?$filter=${string.urlEncode(`C_Payment_ID in (${batch.join(',')})`)}&$select=C_Payment_ID,DateTrx`, 'GET', token, null)
              if (payRes?.records) {
                for (const payment of payRes.records) {
                  paymentDates[payment.id] = payment.DateTrx
                }
              }
            } catch (e) {
              console.warn('Could not fetch payment dates batch:', e)
            }
          }
        }

        // Add total paid amount and payment date to each invoice record
        for (const invoice of res.records) {
          invoice.TotalPaidAmt = Math.abs(allocationSums[invoice.id] || 0)

          // Find latest payment date for this invoice
          const payIds = invoicePaymentIds[invoice.id]
          if (payIds) {
            let latestDate: string | null = null
            payIds.forEach((payId: number) => {
              const date = paymentDates[payId]
              if (date && (!latestDate || date > latestDate)) {
                latestDate = date
              }
            })
            invoice.PaymentDate = latestDate
          }
        }
      }
    } catch (err) {
      console.warn('Could not fetch allocation lines:', err)
    }
  }

  // Fetch order sources in one batch and attach Name/Marketplace to each invoice's C_Order_ID
  if (res?.records?.length > 0) {
    const orderSourceIds = new Set<number>()
    for (const inv of res.records) {
      const osId = inv.C_Order_ID?.C_OrderSource_ID?.id
      if (osId) orderSourceIds.add(osId)
    }

    if (orderSourceIds.size > 0) {
      try {
        const ids = Array.from(orderSourceIds)
        const orderSources: Record<number, any> = {}
        const batchSize = 100
        for (let i = 0; i < ids.length; i += batchSize) {
          const batch = ids.slice(i, i + batchSize)
          const osRes: any = await event.context.fetch(`models/c_ordersource?$filter=${string.urlEncode(`C_OrderSource_ID in (${batch.join(',')})`)}&$select=C_OrderSource_ID,Name,Marketplace`, 'GET', token, null)
          if (osRes?.records) {
            for (const os of osRes.records) {
              orderSources[os.id] = os
            }
          }
        }

        for (const inv of res.records) {
          const osId = inv.C_Order_ID?.C_OrderSource_ID?.id
          if (osId && orderSources[osId]) {
            inv.C_Order_ID.C_OrderSource_ID = {
              ...inv.C_Order_ID.C_OrderSource_ID,
              Name: orderSources[osId].Name,
              Marketplace: orderSources[osId].Marketplace
            }
          }
        }
      } catch (err) {
        console.warn('Could not fetch order sources:', err)
      }
    }
  }

  // Fetch org's business partner to check isAllowFeeReportDownload permission
  let isAllowFeeReportDownload = false
  if (organizationId) {
    try {
      const orgRes: any = await event.context.fetch(`models/ad_org/${organizationId}?$select=C_BPartner_ID`, 'GET', token, null)
      const bpartnerId = orgRes?.C_BPartner_ID?.id

      if (bpartnerId) {
        const bpartnerRes: any = await event.context.fetch(`models/c_bpartner/${bpartnerId}?$select=isAllowFeeReportDownload`, 'GET', token, null)
        isAllowFeeReportDownload = bpartnerRes?.isAllowFeeReportDownload === 'Y'
      }
    } catch (err) {
      console.warn('Could not fetch org business partner permission:', err)
    }
  }

  if(res) {
    data = {
      ...res,
      isAllowFeeReportDownload
    }
  }

  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
})
