import { VoteChoice } from '@prisma/client';

/**
 * Pure logic — mirrors AssembliesService.tallyDelta but in isolation.
 */
function tallyDelta(choice: VoteChoice, weight: number) {
  if (choice === VoteChoice.FOR) return { totalFor: { increment: weight } };
  if (choice === VoteChoice.AGAINST) return { totalAgainst: { increment: weight } };
  return { totalAbstain: { increment: weight } };
}

function applyDelta(
  tally: { totalFor: number; totalAgainst: number; totalAbstain: number },
  delta: { totalFor?: { increment: number }; totalAgainst?: { increment: number }; totalAbstain?: { increment: number } },
) {
  return {
    totalFor: tally.totalFor + (delta.totalFor?.increment ?? 0),
    totalAgainst: tally.totalAgainst + (delta.totalAgainst?.increment ?? 0),
    totalAbstain: tally.totalAbstain + (delta.totalAbstain?.increment ?? 0),
  };
}

describe('Vote tally', () => {
  const zero = { totalFor: 0, totalAgainst: 0, totalAbstain: 0 };

  it('FOR adds to totalFor', () => {
    const t = applyDelta(zero, tallyDelta(VoteChoice.FOR, 50));
    expect(t).toEqual({ totalFor: 50, totalAgainst: 0, totalAbstain: 0 });
  });

  it('AGAINST adds to totalAgainst', () => {
    const t = applyDelta(zero, tallyDelta(VoteChoice.AGAINST, 30));
    expect(t.totalAgainst).toBe(30);
  });

  it('changing vote reverts then applies', () => {
    let t = applyDelta(zero, tallyDelta(VoteChoice.FOR, 40));
    // revert
    t = applyDelta(t, tallyDelta(VoteChoice.FOR, -40));
    // re-cast AGAINST
    t = applyDelta(t, tallyDelta(VoteChoice.AGAINST, 40));
    expect(t).toEqual({ totalFor: 0, totalAgainst: 40, totalAbstain: 0 });
  });

  it('simple majority when FOR > AGAINST + ABSTAIN/2', () => {
    const t = { totalFor: 60, totalAgainst: 30, totalAbstain: 10 };
    const approved = t.totalFor > t.totalAgainst;
    expect(approved).toBe(true);
  });
});
