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')
  const query = getQuery(event)
  
  // Get selected year from query parameter, default to current year
  const selectedYear = query.year ? parseInt(query.year as string) : new Date().getFullYear()

  // Fetch all fulfillment customers with their invoices, orders, and material receipts in one request for better performance
  const res: any = await event.context.fetch(
    `models/c_bpartner?$filter=${string.urlEncode('isFulfillmentCustomer eq true and IsActive eq true')}&$expand=C_Invoice.c_bpartner_id,C_Order.c_bpartner_id,M_InOut.c_bpartner_id&$orderby=${string.urlEncode('Name asc')}`,
    'GET',
    token,
    null
  )

  console.log('═══════════════════════════════════════════════════')
  console.log('FULFILLMENT CUSTOMERS API - DEBUG')
  console.log('═══════════════════════════════════════════════════')
  console.log('Selected Year:', selectedYear)
  console.log('Total customers found:', res?.records?.length || 0)

  if(res) {
    // Process the data to calculate metrics for each customer
    if(res.records && Array.isArray(res.records)) {
      res.records = res.records.map((customer: any) => {
        const allInvoices = customer['C_Invoice.c_bpartner_id'] || []
        const orders = customer['C_Order.c_bpartner_id'] || []
        const allInOuts = customer['M_InOut.c_bpartner_id'] || []

        // Filter completed/closed invoices: IsActive = true, DocStatus = 'CO' or 'CL', IsSOTrx = true
        const invoices = allInvoices.filter((invoice: any) => {
          return invoice.IsActive === true &&
                 (invoice.DocStatus?.id === 'CO' || invoice.DocStatus?.id === 'CL') &&
                 invoice.IsSOTrx === true
        })

        // Filter draft orders separately: IsActive = true, DocStatus = 'DR', IsSOTrx = true
        const draftOrders = orders.filter((order: any) => {
          return order.IsActive === true &&
                 order.DocStatus?.id === 'DR' &&
                 order.IsSOTrx === true
        })

        // Build a lookup map of orders by ID so we can find the related order for each invoice
        const ordersMap: any = {}
        orders.forEach((order: any) => {
          ordersMap[order.id] = order
        })

        // Filter material receipts: IsActive = true, DocStatus = 'CO' or 'CL', IsSOTrx = false (material receipts are purchases)
        // Also ensure the C_BPartner_ID matches the current customer
        const materialReceipts = allInOuts.filter((inout: any) => {
          const bpartnerMatch = inout.C_BPartner_ID?.id === customer.id ||
                                inout.C_BPartner_ID === customer.id ||
                                String(inout.C_BPartner_ID) === String(customer.id)
          return inout.IsActive === true &&
                 (inout.DocStatus?.id === 'CO' || inout.DocStatus?.id === 'CL') &&
                 inout.IsSOTrx === false &&
                 bpartnerMatch
        })

        console.log('---------------------------------------------------')
        console.log('Customer:', customer.Name, '(ID:', customer.id, ')')
        console.log('Total invoices (raw):', allInvoices.length)
        console.log('Filtered invoices:', invoices.length)
        console.log('Total orders:', orders.length)
        console.log('Total material receipts (raw):', allInOuts.length)
        console.log('Filtered material receipts:', materialReceipts.length)
        if(invoices.length > 0) {
          console.log('Sample invoice:', {
            id: invoices[0].id,
            documentNo: invoices[0].DocumentNo,
            dateInvoiced: invoices[0].DateInvoiced,
            grandTotal: invoices[0].GrandTotal,
            docStatus: invoices[0].DocStatus?.id,
            isActive: invoices[0].IsActive,
            isSOTrx: invoices[0].IsSOTrx
          })
        }

        // Calculate total income for all time (using TotalLines - without tax)
        const totalIncome = invoices.reduce((sum: number, invoice: any) => {
          return sum + (parseFloat(invoice.TotalLines) || 0)
        }, 0)

        // Calculate total income for selected year (use related order's PeriodPerformanceDate, fallback to DateInvoiced)
        const yearIncome = invoices.reduce((sum: number, invoice: any) => {
          const relatedOrderId = invoice.C_Order_ID?.id || invoice.C_Order_ID
          const relatedOrder = relatedOrderId ? ordersMap[relatedOrderId] : null
          const dateField = relatedOrder?.PeriodPerformanceDate || invoice.PeriodPerformanceDate || invoice.DateInvoiced
          if(dateField) {
            const invoiceDate = new Date(dateField)
            if(invoiceDate.getFullYear() === selectedYear) {
              return sum + (parseFloat(invoice.TotalLines) || 0)
            }
          }
          return sum
        }, 0)

        // Calculate invoices by month for selected year
        const invoicesByMonth: any = {}

        invoices.forEach((invoice: any) => {
          // Use the related order's PeriodPerformanceDate for month assignment, fallback to invoice's own PeriodPerformanceDate, then DateInvoiced
          const relatedOrderId = invoice.C_Order_ID?.id || invoice.C_Order_ID
          const relatedOrder = relatedOrderId ? ordersMap[relatedOrderId] : null
          const dateField = relatedOrder?.PeriodPerformanceDate || invoice.PeriodPerformanceDate || invoice.DateInvoiced
          if(dateField) {
            const invoiceDate = new Date(dateField)
            const invoiceYear = invoiceDate.getFullYear()
            const invoiceMonth = invoiceDate.getMonth() + 1

            console.log(`  Invoice ${invoice.DocumentNo}: ${dateField} (Year: ${invoiceYear}, Month: ${invoiceMonth}, Selected Year: ${selectedYear})`)

            if(invoiceYear === selectedYear) {
              const month = invoiceMonth // 1-12
              const monthKey = month.toString() // Ensure string key for consistency
              if(!invoicesByMonth[monthKey]) {
                invoicesByMonth[monthKey] = {
                  count: 0,
                  total: 0,
                  draftCount: 0,
                  draftTotal: 0,
                  invoices: [],
                  draftOrders: [],
                  orders: [],
                  firstMaterialReceiptDate: null,
                  firstMaterialReceiptId: null
                }
              }
              invoicesByMonth[monthKey].count++
              // Accumulate raw values, will round later
              invoicesByMonth[monthKey].total += parseFloat(invoice.TotalLines) || 0
              invoicesByMonth[monthKey].invoices.push({
                id: invoice.id,
                documentNo: invoice.DocumentNo,
                dateInvoiced: invoice.DateInvoiced,
                totalLines: invoice.TotalLines,
                grandTotal: invoice.GrandTotal,
                docStatus: invoice.DocStatus,
                isPdfSent: invoice.isPdfSent || false,
                pdfSentTime: invoice.PdfSentTime || null
              })
              console.log(`    -> Added to month ${month} (key: ${monthKey})`)
            }
          }
        })

        // Add draft orders by month for selected year
        draftOrders.forEach((order: any) => {
          // Use PeriodPerformanceDate for month assignment, fallback to DateOrdered if empty/null
          const dateField = order.PeriodPerformanceDate || order.DateOrdered
          if(dateField) {
            const orderDate = new Date(dateField)
            const orderYear = orderDate.getFullYear()
            const orderMonth = orderDate.getMonth() + 1

            if(orderYear === selectedYear) {
              const month = orderMonth // 1-12
              const monthKey = month.toString()
              if(!invoicesByMonth[monthKey]) {
                invoicesByMonth[monthKey] = {
                  count: 0,
                  total: 0,
                  draftCount: 0,
                  draftTotal: 0,
                  invoices: [],
                  draftOrders: [],
                  orders: [],
                  firstMaterialReceiptDate: null,
                  firstMaterialReceiptId: null
                }
              }
              invoicesByMonth[monthKey].draftCount++
              invoicesByMonth[monthKey].draftTotal += parseFloat(order.GrandTotal) || 0
              invoicesByMonth[monthKey].draftOrders.push({
                id: order.id,
                documentNo: order.DocumentNo,
                dateOrdered: order.DateOrdered,
                grandTotal: order.GrandTotal,
                docStatus: order.DocStatus
              })
            }
          }
        })

        // Process material receipts to find the first (earliest) one for all time for this business partner
        console.log(`Processing ${materialReceipts.length} material receipts for ${customer.Name}`)

        let firstMaterialReceipt = null
        if (materialReceipts.length > 0) {
          // Sort all material receipts by MovementDate to find the earliest one ever
          const sortedReceipts = [...materialReceipts].sort((a: any, b: any) => {
            return new Date(a.MovementDate).getTime() - new Date(b.MovementDate).getTime()
          })
          firstMaterialReceipt = sortedReceipts[0]
          console.log(`  -> First material receipt ever for ${customer.Name}: ${firstMaterialReceipt.DocumentNo} (${firstMaterialReceipt.MovementDate}), ID: ${firstMaterialReceipt.id}`)
        }

        // Store the first material receipt in the month where the first invoice/draft exists for the selected year
        if (firstMaterialReceipt) {
          // Find the first month with data in the selected year
          const monthsWithData = Object.keys(invoicesByMonth).map(k => parseInt(k)).sort((a, b) => a - b)
          if (monthsWithData.length > 0) {
            const firstMonthKey = monthsWithData[0].toString()
            invoicesByMonth[firstMonthKey].firstMaterialReceiptDate = firstMaterialReceipt.MovementDate
            invoicesByMonth[firstMonthKey].firstMaterialReceiptId = firstMaterialReceipt.id
            console.log(`  -> Stored first material receipt in month ${firstMonthKey}`)
          }
        }

        console.log('Invoices by month:', Object.keys(invoicesByMonth).map(m => `Month ${m}: ${invoicesByMonth[m].count} invoices, total: ${invoicesByMonth[m].total}, ${invoicesByMonth[m].draftCount} drafts, draft total: ${invoicesByMonth[m].draftTotal}, first receipt: ${invoicesByMonth[m].firstMaterialReceiptDate || 'none'}`))

        // Add draft orders to the month boxes (use PeriodPerformanceDate, fallback to DateOrdered)
        orders.forEach((order: any) => {
          // Check if it's a fulfillment order by checking description
          if(order.Description && order.Description.includes('Fulfillment Invoice')) {
            const dateField = order.PeriodPerformanceDate || order.DateOrdered
            const orderDate = new Date(dateField)
            if(orderDate.getFullYear() === selectedYear) {
              const month = orderDate.getMonth() + 1 // 1-12
              const monthKey = month.toString() // Ensure string key for consistency
              if(!invoicesByMonth[monthKey]) {
                invoicesByMonth[monthKey] = {
                  count: 0,
                  total: 0,
                  draftCount: 0,
                  draftTotal: 0,
                  invoices: [],
                  draftOrders: [],
                  orders: [],
                  firstMaterialReceiptDate: null,
                  firstMaterialReceiptId: null
                }
              }
              invoicesByMonth[monthKey].orders.push({
                id: order.id,
                documentNo: order.DocumentNo,
                dateOrdered: order.DateOrdered,
                grandTotal: order.GrandTotal,
                docStatus: order.DocStatus,
                description: order.Description
              })
              console.log(`    -> Added order to month ${month} (key: ${monthKey})`)
            }
          }
        })

        // Round monthly totals to avoid floating-point precision issues
        Object.keys(invoicesByMonth).forEach(monthKey => {
          invoicesByMonth[monthKey].total = Math.round(invoicesByMonth[monthKey].total * 100) / 100
        })

        const result = {
          ...customer,
          metrics: {
            totalIncome: totalIncome,
            yearIncome: yearIncome,
            totalInvoices: invoices.length,
            invoicesByMonth
          }
        }

        console.log('Final metrics for', customer.Name, ':', {
          totalIncome: result.metrics.totalIncome,
          yearIncome: result.metrics.yearIncome,
          totalInvoices: result.metrics.totalInvoices,
          monthsWithData: Object.keys(result.metrics.invoicesByMonth)
        })

        return result
      })

      // Calculate monthly totals across all customers
      const monthlyTotals: any = {}
      for (let month = 1; month <= 12; month++) {
        monthlyTotals[month] = {
          total: 0,
          count: 0
        }
      }

      res.records.forEach((customer: any) => {
        if (customer.metrics?.invoicesByMonth) {
          Object.keys(customer.metrics.invoicesByMonth).forEach(month => {
            const monthNum = parseInt(month)
            // Keep raw numbers for accurate totals, round only at display time
            monthlyTotals[monthNum].total += customer.metrics.invoicesByMonth[month].total || 0
            monthlyTotals[monthNum].count += customer.metrics.invoicesByMonth[month].count || 0
          })
        }
      })

      // Round monthly totals to 2 decimals to avoid floating-point precision issues
      Object.keys(monthlyTotals).forEach(month => {
        monthlyTotals[month].total = Math.round(monthlyTotals[month].total * 100) / 100
      })

      // === Shipping cost calculation (M_Product_Category_ID = 1000007 "Versandkosten") ===
      // Collect all invoice IDs from all customers
      const allInvoiceIds = new Set<number>()
      res.records.forEach((customer: any) => {
        if (customer.metrics?.invoicesByMonth) {
          Object.values(customer.metrics.invoicesByMonth).forEach((monthData: any) => {
            monthData.invoices?.forEach((inv: any) => {
              allInvoiceIds.add(inv.id)
            })
          })
        }
      })

      console.log('Shipping cost calculation - Total invoice IDs:', allInvoiceIds.size)

      // Fetch each invoice with expanded invoice lines and product data
      // Using the pattern: models/c_invoice/{id}?$expand=c_invoiceline($expand=M_Product_ID)
      const shippingByInvoice: Record<number, number> = {}
      const invoiceIdArray = Array.from(allInvoiceIds)

      for (const invoiceId of invoiceIdArray) {
        try {
          const invoiceRes: any = await event.context.fetch(
            `models/c_invoice/${invoiceId}?$expand=c_invoiceline($expand=M_Product_ID)`,
            'GET', token, null
          )

          if (invoiceRes?.c_invoiceline) {
            invoiceRes.c_invoiceline.forEach((line: any) => {
              const categoryId = line.M_Product_ID?.M_Product_Category_ID?.id
              if (categoryId === 1000007) {
                if (!shippingByInvoice[invoiceId]) shippingByInvoice[invoiceId] = 0
                shippingByInvoice[invoiceId] += parseFloat(line.LineNetAmt) || 0
                console.log('Found shipping line - Invoice:', invoiceId, 'Product:', line.M_Product_ID?.Name, 'Amount:', line.LineNetAmt)
              }
            })
          }
        } catch (e) {
          console.error('Error fetching invoice', invoiceId, ':', e)
        }
      }

      console.log('Shipping amounts by invoice:', shippingByInvoice)

      // Step 4: Enrich customer month data with shipping info
      res.records.forEach((customer: any) => {
        let yearShippingTotal = 0
        if (customer.metrics?.invoicesByMonth) {
          Object.keys(customer.metrics.invoicesByMonth).forEach((monthKey: string) => {
            const monthData = customer.metrics.invoicesByMonth[monthKey]
            let monthShipping = 0
            monthData.invoices?.forEach((inv: any) => {
              monthShipping += shippingByInvoice[inv.id] || 0
            })
            monthData.shippingTotal = Math.round(monthShipping * 100) / 100
            monthData.totalWithoutShipping = Math.round((monthData.total - monthShipping) * 100) / 100
            yearShippingTotal += monthShipping
          })
        }
        customer.metrics.yearShippingTotal = Math.round(yearShippingTotal * 100) / 100
        customer.metrics.yearIncomeWithoutShipping = Math.round(((customer.metrics.yearIncome || 0) - yearShippingTotal) * 100) / 100
      })

      // Step 5: Add shipping info to monthly totals
      Object.keys(monthlyTotals).forEach(month => {
        monthlyTotals[month].shippingTotal = 0
      })

      res.records.forEach((customer: any) => {
        if (customer.metrics?.invoicesByMonth) {
          Object.keys(customer.metrics.invoicesByMonth).forEach(month => {
            const monthNum = parseInt(month)
            monthlyTotals[monthNum].shippingTotal += customer.metrics.invoicesByMonth[month].shippingTotal || 0
          })
        }
      })

      Object.keys(monthlyTotals).forEach(month => {
        monthlyTotals[month].shippingTotal = Math.round(monthlyTotals[month].shippingTotal * 100) / 100
        monthlyTotals[month].totalWithoutShipping = Math.round((monthlyTotals[month].total - monthlyTotals[month].shippingTotal) * 100) / 100
      })

      // Add monthly totals to response
      res.monthlyTotals = monthlyTotals
      res.selectedYear = selectedYear
    }

    data = res
  }

  console.log('═══════════════════════════════════════════════════')

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