import fetchHelper from './fetchHelper'

// Resolves the "Abrechnung" (Accounting) R_RequestType used for billed tickets.
//
// Business rule: as soon as a ticket carries a billed amount (RequestAmt ≠ 0 —
// time was booked via "Zeit abrechnen", a direct amount (positive or a
// negative credit) was added, a mobile task stop, a receive task or an inline
// amount edit) its request type MUST be "Abrechnung". The rule is
// enforced centrally in requests/{update.put,store.post}.ts through
// `enforceAccountingRequestType()` so every client flow is covered without
// having to remember it in each of them.
//
// The type is looked up by name (Abrechnung / Accounting) so template/clone
// instances with different IDs keep working; the well-known prod ID is the
// fallback when the lookup fails. Cached per process (10-min TTL).

const FALLBACK_ACCOUNTING_REQUEST_TYPE_ID = 1000001
const CACHE_TTL_MS = 10 * 60 * 1000

let cached: { id: number, at: number } | null = null

export const resolveAccountingRequestTypeId = async (event: any, token: string | null): Promise<number> => {
  if (cached && (Date.now() - cached.at) < CACHE_TTL_MS) return cached.id
  try {
    const res: any = await fetchHelper(event, 'models/r_requesttype?$filter=IsActive%20eq%20true&$top=100', 'GET', token, null)
    const records: any[] = res?.records || []
    const match = records.find((rt) => /^abrechnung$/i.test(String(rt?.Name || '').trim()))
      || records.find((rt) => /^accounting$/i.test(String(rt?.Name || '').trim()))
      || records.find((rt) => /abrechnung|accounting/i.test(String(rt?.Name || '')))
    const id = Number(match?.id)
    if (Number.isFinite(id) && id > 0) {
      cached = { id, at: Date.now() }
      return id
    }
  } catch (err: any) {
    console.warn('[accountingRequestType] lookup failed, using fallback', err?.message || err)
  }
  return FALLBACK_ACCOUNTING_REQUEST_TYPE_ID
}

// True when the incoming write carries a non-zero billed amount. Negative
// amounts count too: a credit ticket (e.g. -12,50 € goodwill) must also become
// "Abrechnung", otherwise the nightly request → fee-line SQL in
// ../logship-scripts (filters on r_requesttype_id = Abrechnung) never picks it
// up and the credit would silently never reach the customer's invoice order.
export const hasBilledAmount = (requestAmt: any): boolean => {
  if (requestAmt === null || requestAmt === undefined || requestAmt === '') return false
  const n = typeof requestAmt === 'number' ? requestAmt : Number(String(requestAmt).replace(',', '.'))
  return Number.isFinite(n) && n !== 0
}

// Mutates `newObjValue` so the iDempiere write sets R_RequestType_ID to the
// accounting type whenever the body carries a billed amount. Returns the id
// that was enforced (or null when the rule did not apply).
export const enforceAccountingRequestType = async (event: any, token: string | null, body: any, newObjValue: any): Promise<number | null> => {
  if (!hasBilledAmount(body?.requestAmt)) return null
  const id = await resolveAccountingRequestTypeId(event, token)
  newObjValue.R_RequestType_ID = { id, tableName: 'R_RequestType' }
  return id
}
