import refreshTokenHelper from '../../utils/refreshTokenHelper'
import fetchHelper from '../../utils/fetchHelper'

// iDempiere REST expects ISO-8601 with explicit timezone for timestamptz
// columns — e.g. `2026-04-14T12:09:03Z` (no milliseconds).
const toIDempiereTs = (iso: any): string | undefined => {
  if (!iso) return undefined
  try {
    const d = new Date(String(iso))
    if (Number.isNaN(d.getTime())) return undefined
    return d.toISOString().replace(/\.\d{3}Z$/, 'Z')
  } catch {
    return undefined
  }
}

const writeOne = async (event: any, e: any, token: string, adOrgId: number) => {
  const body: Record<string, any> = {
    AD_Org_ID: { id: adOrgId, tableName: 'AD_Org' },
    sessionUID: e.sessionUID,
    actionType: e.actionType,
    isActive: true,
    tableName: 'CUST_CommissionActivity',
  }

  const actionTime = toIDempiereTs(e.actionTime)
  if (actionTime) body.actionTime = actionTime

  // Only include FK keys when we actually have an id — iDempiere rejects
  // explicit null for any FK column marked Mandatory, and treats "key missing"
  // as "leave blank" for non-mandatory ones.
  if (e.adUserId)        body.AD_User_ID        = { id: Number(e.adUserId),        tableName: 'AD_User' }
  if (e.mInoutId)        body.M_InOut_ID        = { id: Number(e.mInoutId),        tableName: 'M_InOut' }
  if (e.cOrderId)        body.C_Order_ID        = { id: Number(e.cOrderId),        tableName: 'C_Order' }
  if (e.mProductId)      body.M_Product_ID      = { id: Number(e.mProductId),      tableName: 'M_Product' }
  if (e.cBPartnerId)     body.C_BPartner_ID     = { id: Number(e.cBPartnerId),     tableName: 'C_BPartner' }
  if (e.foreignAdOrgId)  body.Foreign_AD_Org_ID = { id: Number(e.foreignAdOrgId),  tableName: 'AD_Org' }

  if (e.qty != null) body.qty = e.qty
  if (e.durationMs != null) body.durationMs = e.durationMs
  if (e.shippingService) body.shippingService = e.shippingService
  if (e.description) body.description = e.description

  return fetchHelper(event, 'models/cust_commissionactivity', 'POST', token, body)
}

const isAuthError = (reason: any): boolean => {
  const code = String(reason?.statusCode ?? reason?.response?.status ?? '')
  return code === '401' || code === '403'
}

const handleBatch = async (event: any, events: any[]) => {
  let token: string | null = null
  try {
    token = await getTokenHelper(event)
  } catch {
    return
  }
  const adOrgId = Number(getCookie(event, 'logship_organization_id'))
  if (!token || !adOrgId) return

  const results = await Promise.allSettled(events.map((e) => writeOne(event, e, token as string, adOrgId)))
  const needsRefresh = results.some((r) => r.status === 'rejected' && isAuthError((r as any).reason))

  const firstFailure = results.find((r) => r.status === 'rejected') as PromiseRejectedResult | undefined
  if (firstFailure && !needsRefresh) {
    const reason: any = firstFailure.reason
    console.error('[commission-activity] iDempiere write rejected:', {
      statusCode: reason?.statusCode ?? reason?.response?.status,
      message: reason?.message,
      data: reason?.data,
    })
  }

  if (!needsRefresh) return

  try {
    const fresh: any = await refreshTokenHelper(event)
    if (!fresh) return
    const retry = await Promise.allSettled(events.map((e) => writeOne(event, e, fresh, adOrgId)))
    const retryFailure = retry.find((r) => r.status === 'rejected') as PromiseRejectedResult | undefined
    if (retryFailure) {
      const reason: any = retryFailure.reason
      console.error('[commission-activity] iDempiere write rejected after token refresh:', {
        statusCode: reason?.statusCode ?? reason?.response?.status,
        message: reason?.message,
        data: reason?.data,
      })
    }
  } catch (e: any) {
    console.error('[commission-activity] token refresh failed:', e?.message)
  }
}

export default defineEventHandler(async (event) => {
  let body: any = null
  try {
    body = await readBody(event)
  } catch {
    body = null
  }

  const events: any[] = Array.isArray(body?.events) ? body.events : []

  if (events.length) {
    handleBatch(event, events).catch(() => {})
  }

  setResponseStatus(event, 204)
  return null
})
