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

/**
 * Dunning gate status for the current organization's linked business partner.
 *
 * Reads two Yes-No flags on the org's C_BPartner:
 *  - IsTerminationNotice → warning modal on each login (last reminder before termination)
 *  - IsTerminated       → permanent blocking modal until the flag is cleared
 *
 * When either flag is set, also returns the partner's open (unpaid) invoices so the
 * modal can list them. Fail-soft in every branch: any error (including the columns
 * not existing in iDempiere yet) returns the inactive shape — an API hiccup must
 * never lock users out or pop a false modal.
 */
const INACTIVE = { notice: false, terminated: false, invoices: [], totalOpen: 0, sessionKey: '' }

const handleFunc = async (event: any, authToken: any = null) => {
  const config = useRuntimeConfig()
  const serviceToken = config.api.idempieretoken
  const organizationId = getCookie(event, 'logship_organization_id')
  // logship_session is httpOnly and regenerated on every login — expose a short
  // key so the client can show the notice once per login without reading the cookie.
  const sessionKey = String(getCookie(event, 'logship_session') || '').slice(-12)

  if (!organizationId || !serviceToken) {
    return { ...INACTIVE }
  }

  try {
    // Resolve the org's linked business partner
    const orgFilter = `AD_Org_ID eq ${organizationId}`
    const orgUrl = `${config.api.url}/models/ad_org?$filter=${string.urlEncode(orgFilter)}&$select=C_BPartner_ID`

    const orgRes: any = await $fetch(orgUrl, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
        Authorization: 'Bearer ' + serviceToken
      }
    })

    const bpartnerId = orgRes?.records?.[0]?.C_BPartner_ID?.id
    if (!bpartnerId) {
      return { ...INACTIVE, sessionKey }
    }

    // Read the two flags. Own try/catch: while the custom columns don't exist in
    // iDempiere yet, the $select errors — treat as inactive (fail-soft).
    let notice = false
    let terminated = false
    try {
      const bpartnerRes: any = await $fetch(`${config.api.url}/models/c_bpartner/${bpartnerId}?$select=IsTerminationNotice,IsTerminated`, {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json',
          Authorization: 'Bearer ' + serviceToken
        }
      })
      const rawNotice = bpartnerRes?.IsTerminationNotice ?? bpartnerRes?.isTerminationNotice
      const rawTerminated = bpartnerRes?.IsTerminated ?? bpartnerRes?.isTerminated
      notice = rawNotice === true || rawNotice === 'Y'
      terminated = rawTerminated === true || rawTerminated === 'Y'
    } catch (err) {
      return { ...INACTIVE, sessionKey }
    }

    if (!notice && !terminated) {
      return { ...INACTIVE, sessionKey }
    }

    // Fetch open invoices of the partner. Do NOT scope by AD_Org_ID: fulfillment
    // invoices are issued BY LogYou TO the merchant, so they are booked under the
    // issuing LogYou org — never under the merchant's cookie org (see ffn-unpaid-count).
    const invoiceFilter = `C_BPartner_ID eq ${bpartnerId} and IsPaid eq 'N' and (DocStatus eq 'CO' or DocStatus eq 'CL')`
    const invoiceUrl = `${config.api.url}/models/C_Invoice?$filter=${string.urlEncode(invoiceFilter)}&$select=C_Invoice_ID,DocumentNo,DateInvoiced,GrandTotal,IsPaid,C_Currency_ID&$orderby=DateInvoiced asc`

    const res: any = await $fetch(invoiceUrl, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
        Authorization: 'Bearer ' + serviceToken
      }
    })

    const records = res?.records || []

    // Cross-check allocations (IsPaid can lag behind completed payments)
    let allocationSums: Record<number, number> = {}
    if (records.length > 0) {
      try {
        const invoiceIds = records.map((inv: any) => inv.id)
        const allocUrl = `${config.api.url}/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)`
        const allocRes: any = await $fetch(allocUrl, {
          method: 'GET',
          headers: {
            'Content-Type': 'application/json',
            Accept: 'application/json',
            Authorization: 'Bearer ' + serviceToken
          }
        })

        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)
          }
        }
      } catch (err) {
        // If allocations fail, treat all fetched invoices as unpaid
      }
    }

    const invoices: any[] = []
    let totalOpen = 0
    for (const inv of records) {
      const paidAmt = Math.abs(allocationSums[inv.id] || 0)
      const grandTotal = Math.abs(inv.GrandTotal || 0)
      const openAmt = grandTotal - paidAmt
      if (openAmt > 0.009) {
        invoices.push({
          id: inv.id,
          documentNo: inv.DocumentNo,
          dateInvoiced: inv.DateInvoiced,
          grandTotal: inv.GrandTotal,
          openAmt: Math.round(openAmt * 100) / 100,
          currency: inv.C_Currency_ID?.identifier || 'EUR'
        })
        totalOpen += openAmt
      }
    }

    return {
      notice,
      terminated,
      invoices,
      totalOpen: Math.round(totalOpen * 100) / 100,
      sessionKey
    }
  } catch (err) {
    console.warn('Could not fetch termination status:', err)
    return { ...INACTIVE, sessionKey }
  }
}

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

  return data
})
