import { describe, test, expect } from "bun:test";
import { createPoll, addOption, vote, unvote, hasVoted } from "../poll.js";

describe("createPoll", () => {
  test("returns poll with title and empty options", () => {
    const poll = createPoll("Favorite color?");
    expect(poll.title).toBe("Favorite color?");
    expect(poll.options).toEqual([]);
  });
});

describe("addOption", () => {
  test("appends option with text, id, and empty votes", () => {
    const poll = createPoll("Test");
    addOption(poll, "Red");

    expect(poll.options).toHaveLength(1);
    expect(poll.options[0]!.text).toBe("Red");
    expect(poll.options[0]!.id).toBeDefined();
    expect(poll.options[0]!.votes).toEqual([]);
  });

  test("appends multiple options", () => {
    const poll = createPoll("Test");
    addOption(poll, "Red");
    addOption(poll, "Blue");

    expect(poll.options).toHaveLength(2);
    expect(poll.options[0]!.text).toBe("Red");
    expect(poll.options[1]!.text).toBe("Blue");
  });
});

describe("vote", () => {
  test("adds peer ID to option's votes array", () => {
    const poll = createPoll("Test");
    addOption(poll, "Red");
    const optionId = poll.options[0]!.id;

    vote(poll, optionId, "peer-1");

    expect(poll.options[0]!.votes).toEqual(["peer-1"]);
  });

  test("prevents double-vote (no duplicate entries)", () => {
    const poll = createPoll("Test");
    addOption(poll, "Red");
    const optionId = poll.options[0]!.id;

    vote(poll, optionId, "peer-1");
    vote(poll, optionId, "peer-1");

    expect(poll.options[0]!.votes).toEqual(["peer-1"]);
    expect(poll.options[0]!.votes).toHaveLength(1);
  });

  test("allows different peers to vote", () => {
    const poll = createPoll("Test");
    addOption(poll, "Red");
    const optionId = poll.options[0]!.id;

    vote(poll, optionId, "peer-1");
    vote(poll, optionId, "peer-2");

    expect(poll.options[0]!.votes).toEqual(["peer-1", "peer-2"]);
  });
});

describe("unvote", () => {
  test("removes peer ID from votes array", () => {
    const poll = createPoll("Test");
    addOption(poll, "Red");
    const optionId = poll.options[0]!.id;

    vote(poll, optionId, "peer-1");
    unvote(poll, optionId, "peer-1");

    expect(poll.options[0]!.votes).toEqual([]);
  });

  test("does nothing if peer has not voted", () => {
    const poll = createPoll("Test");
    addOption(poll, "Red");
    const optionId = poll.options[0]!.id;

    unvote(poll, optionId, "peer-1");

    expect(poll.options[0]!.votes).toEqual([]);
  });
});

describe("hasVoted", () => {
  test("returns true when peer has voted", () => {
    const poll = createPoll("Test");
    addOption(poll, "Red");
    const optionId = poll.options[0]!.id;

    vote(poll, optionId, "peer-1");

    expect(hasVoted(poll, optionId, "peer-1")).toBe(true);
  });

  test("returns false when peer has not voted", () => {
    const poll = createPoll("Test");
    addOption(poll, "Red");
    const optionId = poll.options[0]!.id;

    expect(hasVoted(poll, optionId, "peer-1")).toBe(false);
  });

  test("returns false for non-existent option", () => {
    const poll = createPoll("Test");
    expect(hasVoted(poll, "non-existent", "peer-1")).toBe(false);
  });
});
