const test = require('node:test');
const assert = require('node:assert/strict');

const {
  buildTrackerRow,
  getCycleRange,
  resolveDueDate,
} = require('../services/statusService');

function bill(overrides = {}) {
  return {
    id: 1,
    name: 'Test bill',
    due_day: 15,
    expected_amount: 100,
    autopay_enabled: 0,
    autodraft_status: 'none',
    cycle_type: 'monthly',
    cycle_day: '1',
    ...overrides,
  };
}

test('monthly bills use due_day and calendar-month cycle range', () => {
  const monthly = bill({ due_day: 31, cycle_day: '1' });

  assert.equal(resolveDueDate(monthly, 2026, 2), '2026-02-28');
  assert.deepEqual(getCycleRange(2026, 2, monthly), {
    start: '2026-02-01',
    end: '2026-02-28',
  });
});

test('weekly bills use cycle_day as weekday', () => {
  const weekly = bill({ cycle_type: 'weekly', cycle_day: 'wednesday' });

  assert.equal(resolveDueDate(weekly, 2026, 5), '2026-05-06');
  assert.deepEqual(getCycleRange(2026, 5, weekly), {
    start: '2026-05-06',
    end: '2026-05-12',
  });
});

test('biweekly bills use cycle_day weekday on the deterministic two-week cadence', () => {
  const biweekly = bill({ cycle_type: 'biweekly', cycle_day: 'monday' });

  assert.equal(resolveDueDate(biweekly, 2026, 5), '2026-05-04');
  assert.deepEqual(getCycleRange(2026, 5, biweekly), {
    start: '2026-05-04',
    end: '2026-05-17',
  });
});

test('quarterly bills only occur in assigned quarter months', () => {
  const quarterly = bill({ cycle_type: 'quarterly', cycle_day: '2', due_day: 30 });

  assert.equal(resolveDueDate(quarterly, 2026, 2), '2026-02-28');
  assert.equal(resolveDueDate(quarterly, 2026, 3), null);
  assert.equal(resolveDueDate(quarterly, 2026, 5), '2026-05-30');
  assert.deepEqual(getCycleRange(2026, 5, quarterly), {
    start: '2026-05-01',
    end: '2026-07-31',
  });
});

test('annual bills only occur in their assigned month', () => {
  const annual = bill({ cycle_type: 'annual', cycle_day: '11', due_day: 31 });

  assert.equal(resolveDueDate(annual, 2026, 10), null);
  assert.equal(resolveDueDate(annual, 2026, 11), '2026-11-30');
  assert.deepEqual(getCycleRange(2026, 11, annual), {
    start: '2026-01-01',
    end: '2026-12-31',
  });
});

test('tracker rows are skipped when a bill does not occur in the requested month', () => {
  const quarterly = bill({ cycle_type: 'quarterly', cycle_day: '1' });

  assert.equal(buildTrackerRow(quarterly, [], 2026, 2, '2026-02-01', { gracePeriodDays: 5 }), null);
});

test('tracker rows cap due math when a payment exceeds the amount due', () => {
  const row = buildTrackerRow(
    bill({ expected_amount: 10000 }),
    [{ amount: 12500, paid_date: '2026-05-10' }],
    2026,
    5,
    '2026-05-16',
    { gracePeriodDays: 5 },
  );

  assert.equal(row.status, 'paid');
  assert.equal(row.total_paid, 125);
  assert.equal(row.paid_toward_due, 100);
  assert.equal(row.overpaid_amount, 25);
  assert.equal(row.balance, 0);
});
