/**
 * iDempiere's REST API serialises Timestamp columns as the server's *local*
 * (Europe/Berlin) wall-clock with a literal "Z" appended — e.g.
 * "2026-06-03T14:30:00Z", where 14:30 is ALREADY Berlin local time, not UTC.
 *
 * Parsing that string with `new Date()` makes the client re-apply the UTC
 * offset, pushing the displayed time 1h (CET, winter) / 2h (CEST, summer) into
 * the future. The old workaround hard-coded `setHours(getHours() - 1)`, which
 * is wrong half the year because it doesn't track daylight-saving time.
 *
 * This helper reads the wall-clock components verbatim and rebuilds a *local*
 * Date, so the timestamp renders exactly as iDempiere recorded it — no timezone
 * double-offset, no DST-dependent manual correction. It tolerates the common
 * shapes iDempiere / Postgres views emit (trailing `Z`, fractional seconds, a
 * real `±hh:mm` offset, a space instead of `T`, or a date-only value).
 *
 * Returns `null` for empty / unparseable input.
 */
export const parseIdempiereTimestamp = (value: any): Date | null => {
  if (value === null || value === undefined || value === '') return null
  if (value instanceof Date) return isNaN(value.getTime()) ? null : value

  const str = String(value)

  // YYYY-MM-DD[ T]HH:MM[:SS][.fff][Z|±hh:mm] — keep the wall-clock, drop the zone.
  const dt = str.match(/^(\d{4})-(\d{1,2})-(\d{1,2})[T ](\d{1,2}):(\d{2})(?::(\d{2}))?/)
  if (dt) {
    return new Date(+dt[1], +dt[2] - 1, +dt[3], +dt[4], +dt[5], +(dt[6] || 0))
  }

  // Date-only "YYYY-MM-DD" → local midnight (avoids the UTC-parsing day shift).
  const d = str.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/)
  if (d) {
    return new Date(+d[1], +d[2] - 1, +d[3])
  }

  // Fallback: epoch number or anything else the Date constructor understands.
  const parsed = new Date(value)
  return isNaN(parsed.getTime()) ? null : parsed
}

const pad2 = (n: number): string => String(n).padStart(2, '0')

/**
 * German date display: `dd.mm.yyyy`. Accepts everything `parseIdempiereTimestamp`
 * understands (Laravel `Y-m-d` / `Y-m-d H:i:s`, iDempiere `…T..Z`, Date).
 * Returns '' for empty / unparseable input.
 */
export const formatDateDE = (value: any): string => {
  const d = parseIdempiereTimestamp(value)
  return d ? `${pad2(d.getDate())}.${pad2(d.getMonth() + 1)}.${d.getFullYear()}` : ''
}

/** German date-time display: `dd.mm.yyyy HH:MM`. '' for empty / unparseable input. */
export const formatDateTimeDE = (value: any): string => {
  const d = parseIdempiereTimestamp(value)
  return d ? `${formatDateDE(d)} ${pad2(d.getHours())}:${pad2(d.getMinutes())}` : ''
}

/**
 * Local-time `YYYY-MM-DD` (what the API expects). Never `toISOString()` — that
 * is UTC and shifts the day late in the evening (Europe/Berlin).
 */
export const toLocalISODate = (d: Date): string => {
  return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`
}

/** `YYYY-MM-DD` ± n days, computed in local time. Falls back to today for bad input. */
export const addDaysISO = (iso: any, days: number): string => {
  const d = parseIdempiereTimestamp(iso) || new Date()
  d.setDate(d.getDate() + days)
  return toLocalISODate(d)
}
