import type { Forecast } from '@commitea/core'

const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

/** Advance `base` by whole working days (skipping Sat/Sun). Fractions round to nearest day. */
export function addWorkingDays(base: Date, workingDays: number): Date {
  const d = new Date(base.getFullYear(), base.getMonth(), base.getDate())
  let remaining = Math.max(0, Math.round(workingDays))
  while (remaining > 0) {
    d.setDate(d.getDate() + 1)
    const day = d.getDay()
    if (day !== 0 && day !== 6) remaining -= 1
  }
  return d
}

/** "Mar 6" */
export function formatShort(d: Date): string {
  return `${MONTHS[d.getMonth()]} ${d.getDate()}`
}

/** "Feb 24 – Mar 6" (collapses the month when both ends share it → "Mar 3–12"). */
export function formatRange(lo: Date, hi: Date): string {
  if (lo.getMonth() === hi.getMonth()) return `${MONTHS[lo.getMonth()]} ${lo.getDate()}–${hi.getDate()}`
  return `${formatShort(lo)} – ${formatShort(hi)}`
}

export interface BurnUpBandPoint {
  fraction: number
  loDay: number
  midDay: number
  hiDay: number
}

/** Chart-ready geometry + calendar labels derived from a Monte Carlo forecast. */
export interface BurnUpData {
  scope: number
  horizonDays: number
  band: BurnUpBandPoint[]
  p80Day: number
  p80Label: string
  rangeLabel: string
  startLabel: string
  endLabel: string
}

/**
 * Map a working-day forecast onto a calendar-anchored burn-up cone. `today`
 * anchors day 0; the cone emanates from (today, 0) and widens to the right.
 * The historical "actual" polyline behind today awaits lifecycle events (#5).
 */
export function buildBurnUpData(f: Forecast, today: Date): BurnUpData | null {
  if (f.scope === 0 || f.curve.length === 0) return null
  const last = f.curve[f.curve.length - 1]
  const horizonDays = Math.max(1, Math.ceil(last.p90Day * 1.05))
  const band: BurnUpBandPoint[] = [
    { fraction: 0, loDay: 0, midDay: 0, hiDay: 0 },
    ...f.curve.map((p) => ({ fraction: p.fraction, loDay: p.p10Day, midDay: p.p50Day, hiDay: p.p90Day })),
  ]
  return {
    scope: f.scope,
    horizonDays,
    band,
    p80Day: f.p80Day,
    p80Label: formatShort(addWorkingDays(today, f.p80Day)),
    rangeLabel: formatRange(addWorkingDays(today, f.p50Day), addWorkingDays(today, last.p90Day)),
    startLabel: formatShort(today),
    endLabel: formatShort(addWorkingDays(today, horizonDays)),
  }
}
