import { getUserVotes, updateFeatureVote, getVotingStats } from '../voting';
import { resetMemoryStorage } from '../storage/memory';
import { FeatureRequest } from '../../../types/gen/types.gen';

const OPT_A = FeatureRequest.STATISTICS;
const OPT_B = FeatureRequest.UI;

beforeEach(() => {
    resetMemoryStorage();
});

describe('updateFeatureVote', () => {
    test('přidá hlas pro nového uživatele', async () => {
        const result = await updateFeatureVote('alice', OPT_A, true);
        expect(result['alice']).toContain(OPT_A);
    });

    test('vyhodí chybu při duplicitním hlasování', async () => {
        await updateFeatureVote('alice', OPT_A, true);
        await expect(updateFeatureVote('alice', OPT_A, true)).rejects.toThrow('hlasovali');
    });

    test('odebere hlas', async () => {
        await updateFeatureVote('alice', OPT_A, true);
        await updateFeatureVote('alice', OPT_A, false);
        const stats = await getVotingStats();
        expect(stats[OPT_A] ?? 0).toBe(0);
    });

    test('odebrání neexistujícího hlasu je no-op', async () => {
        await expect(updateFeatureVote('alice', OPT_A, false)).resolves.not.toThrow();
    });

    test('odebrání posledního hlasu odstraní login ze storage', async () => {
        await updateFeatureVote('alice', OPT_A, true);
        const data = await updateFeatureVote('alice', OPT_A, false);
        expect('alice' in data).toBe(false);
    });

    test('vyhodí chybu po 4 hlasech', async () => {
        const options = Object.values(FeatureRequest);
        for (let i = 0; i < 4; i++) {
            await updateFeatureVote('alice', options[i], true);
        }
        await expect(updateFeatureVote('alice', options[4], true)).rejects.toThrow('4');
    });
});

describe('getUserVotes', () => {
    test('vrátí hlasy uživatele', async () => {
        await updateFeatureVote('alice', OPT_A, true);
        const votes = await getUserVotes('alice');
        expect(votes).toContain(OPT_A);
    });

    test('vrátí prázdné pole pro uživatele bez hlasů', async () => {
        const votes = await getUserVotes('neexistujici');
        expect(votes).toEqual([]);
    });
});

describe('getVotingStats', () => {
    test('vrátí agregované počty hlasů', async () => {
        await updateFeatureVote('alice', OPT_A, true);
        await updateFeatureVote('bob', OPT_A, true);
        await updateFeatureVote('bob', OPT_B, true);

        const stats = await getVotingStats();
        expect(stats[OPT_A]).toBe(2);
        expect(stats[OPT_B]).toBe(1);
    });

    test('vrátí prázdný objekt bez hlasů', async () => {
        const stats = await getVotingStats();
        expect(stats).toEqual({});
    });
});
