// Associate Doctor Pay engine — pure calculation, no UI.
//
// Model (confirmed with the practice):
//   • Net production        = actual production − lab fees
//   • Tier %                = flat rate looked up on net production. Tier 1
//                             is the FLOOR (applies from $0 up to the Tier 2
//                             threshold); higher tiers apply from their
//                             threshold upward. Not marginal — one rate on the
//                             whole net figure.
//   • Compensation          = net production × tier %
//   • Earned in month       = compensation − total daily minimum (the monthly
//                             guarantee). Positive = surplus, negative = shortfall.
//   • Draw (a "loan")        = a shortfall. It accrues to a running balance the
//                             doctor owes the practice.
//   • A surplus month first pays down any outstanding draw; only the remainder
//     is paid out as a real bonus.
//   • A draw still outstanding at the end of the 3-month period is reported as
//     owed by the doctor.

// Look up the tier % for a net-production figure.
// tiers: [{ threshold, pct }, ...] ascending. tiers[0] is the floor.
// Returns { pct, index }.
function lookupTier(net, tiers) {
  let pct = tiers[0].pct;
  let index = 0;
  for (let i = 1; i < tiers.length; i++) {
    if (net >= tiers[i].threshold) {
      pct = tiers[i].pct;
      index = i;
    }
  }
  return { pct, index };
}

// Compute the full 3-month schedule.
// tiers:  [{ threshold, pct(0..1) }, ...]
// months: [{ actual, min, lab }, ...] (numbers)
// openingDraw: draw carried in from before month 1 (positive = owed).
function computeAssociatePay(tiers, months, openingDraw = 0) {
  let running = Number(openingDraw) || 0;
  const rows = months.map((m) => {
    const actual = Number(m.actual) || 0;
    const min = Number(m.min) || 0;
    const lab = Number(m.lab) || 0;

    const net = actual - lab;
    const { pct, index } = lookupTier(net, tiers);
    const comp = net * pct;
    const earned = comp - min;
    const open = running;

    let bonusPaid = 0;
    let drawTaken = 0;
    let drawRepaid = 0;

    if (earned >= 0) {
      drawRepaid = Math.min(open, earned);
      running = open - drawRepaid;
      bonusPaid = earned - drawRepaid;
    } else {
      drawTaken = -earned;
      running = open + drawTaken;
    }

    return {
      actual, lab, min,
      net, pct, tierIndex: index,
      comp, earned,
      openDraw: open,
      drawTaken, drawRepaid,
      bonusPaid,
      endDraw: running,
    };
  });

  const sum = (k) => rows.reduce((s, r) => s + r[k], 0);
  const totalBonusPaid = sum('bonusPaid');
  const totalDrawTaken = sum('drawTaken');
  const totalDrawRepaid = sum('drawRepaid');
  const totalNet = sum('net');
  const totalComp = sum('comp');
  const totalDailyMin = sum('min');
  const totalEarned = sum('earned');
  const endingDraw = running;
  const totalPaid = totalDailyMin + totalBonusPaid;

  return {
    rows,
    openingDraw: Number(openingDraw) || 0,
    totalBonusPaid,
    totalDrawTaken,
    totalDrawRepaid,
    totalNet,
    totalComp,
    totalDailyMin,
    totalEarned,
    totalPaid,
    endingDraw,
  };
}

// Month-end date helpers.
// y: full year, m: 0-indexed month. Returns the 3 period-end Dates.
function periodMonthEnds(y, m) {
  const ends = [];
  for (let i = 0; i < 3; i++) {
    ends.push(new Date(y, m + i + 1, 0));
  }
  return ends;
}

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

function fmtMonthEnd(d) {
  return `${MONTH_ABBR[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()}`;
}

function fmtMonthLabel(d) {
  return `${MONTH_ABBR[d.getMonth()]} ${d.getFullYear()}`;
}

window.computeAssociatePay = computeAssociatePay;
window.lookupTier = lookupTier;
window.periodMonthEnds = periodMonthEnds;
window.fmtMonthEnd = fmtMonthEnd;
window.fmtMonthLabel = fmtMonthLabel;
