import { describe, it, expect, beforeEach, vi } from 'vitest';
import type { KuldvillakGame } from '$lib/types/kuldvillak';
import { DEFAULT_SETTINGS, DEFAULT_STATE } from '$lib/types/kuldvillak';

// Mock localStorage
const localStorageMock = (() => {
    let store: Record<string, string> = {};
    return {
        getItem: vi.fn((key: string) => store[key] ?? null),
        setItem: vi.fn((key: string, value: string) => { store[key] = value; }),
        removeItem: vi.fn((key: string) => { delete store[key]; }),
        clear: vi.fn(() => { store = {}; }),
        get length() { return Object.keys(store).length; },
        key: vi.fn((i: number) => Object.keys(store)[i] ?? null),
    };
})();

Object.defineProperty(global, 'localStorage', { value: localStorageMock });

// Import after mocking localStorage
import {
    getKuldvillakGamesList,
    getAllKuldvillakGames,
    loadKuldvillakGame,
    saveKuldvillakGame,
    deleteKuldvillakGame,
    duplicateKuldvillakGame,
    setActiveKuldvillakGame,
    getActiveKuldvillakGameId,
} from './persistence';

// Helper to create a test game
function createTestGame(overrides: Partial<KuldvillakGame> = {}): KuldvillakGame {
    return {
        id: 'test-game-id',
        name: 'Test Game',
        createdAt: '2024-01-01T00:00:00.000Z',
        updatedAt: '2024-01-01T00:00:00.000Z',
        settings: { ...DEFAULT_SETTINGS },
        teams: [
            { id: 'team-1', name: 'Team 1', score: 0 },
            { id: 'team-2', name: 'Team 2', score: 0 },
        ],
        rounds: [{
            id: 'round-1',
            name: 'Round 1',
            pointMultiplier: 1,
            categories: [{
                id: 'cat-1',
                name: 'Category 1',
                questions: [{
                    id: 'q-1',
                    question: 'Test Question',
                    answer: 'Test Answer',
                    points: 100,
                    isDailyDouble: false,
                    isRevealed: false,
                }],
            }],
        }],
        finalRound: null,
        state: { ...DEFAULT_STATE },
        ...overrides,
    };
}

describe('Persistence', () => {
    beforeEach(() => {
        localStorageMock.clear();
        vi.clearAllMocks();
    });

    describe('saveKuldvillakGame', () => {
        it('should save a new game', () => {
            const game = createTestGame();
            const result = saveKuldvillakGame(game);

            expect(result).toBe(true);
            expect(localStorageMock.setItem).toHaveBeenCalled();
        });

        it('should update existing game', () => {
            const game = createTestGame();
            saveKuldvillakGame(game);

            game.name = 'Updated Name';
            saveKuldvillakGame(game);

            const games = getAllKuldvillakGames();
            expect(games).toHaveLength(1);
            expect(games[0].name).toBe('Updated Name');
        });

        it('should update the updatedAt timestamp', () => {
            const game = createTestGame();
            const originalUpdatedAt = game.updatedAt;

            // Wait a tiny bit to ensure different timestamp
            saveKuldvillakGame(game);

            const games = getAllKuldvillakGames();
            expect(games[0].updatedAt).not.toBe(originalUpdatedAt);
        });
    });

    describe('loadKuldvillakGame', () => {
        it('should return null for non-existent game', () => {
            const result = loadKuldvillakGame('non-existent-id');
            expect(result).toBeNull();
        });

        it('should load existing game', () => {
            const game = createTestGame();
            saveKuldvillakGame(game);

            const loaded = loadKuldvillakGame(game.id);
            expect(loaded).not.toBeNull();
            expect(loaded?.name).toBe(game.name);
        });
    });

    describe('deleteKuldvillakGame', () => {
        it('should delete a game', () => {
            const game = createTestGame();
            saveKuldvillakGame(game);

            const result = deleteKuldvillakGame(game.id);

            expect(result).toBe(true);
            expect(getAllKuldvillakGames()).toHaveLength(0);
        });

        it('should handle deleting non-existent game', () => {
            const result = deleteKuldvillakGame('non-existent');
            expect(result).toBe(true); // Should not fail
        });
    });

    describe('duplicateKuldvillakGame', () => {
        it('should create a duplicate with new ID', () => {
            const original = createTestGame();
            saveKuldvillakGame(original);

            const duplicate = duplicateKuldvillakGame(original.id);

            expect(duplicate).not.toBeNull();
            expect(duplicate?.id).not.toBe(original.id);
            expect(duplicate?.name).toBe(`${original.name} (Copy)`);
        });

        it('should reset game state in duplicate', () => {
            const original = createTestGame();
            original.state.phase = 'board';
            original.teams[0].score = 500;
            saveKuldvillakGame(original);

            const duplicate = duplicateKuldvillakGame(original.id);

            expect(duplicate?.state.phase).toBe('lobby');
            expect(duplicate?.teams[0].score).toBe(0);
        });

        it('should reset revealed questions in duplicate', () => {
            const original = createTestGame();
            original.rounds[0].categories[0].questions[0].isRevealed = true;
            saveKuldvillakGame(original);

            const duplicate = duplicateKuldvillakGame(original.id);

            expect(duplicate?.rounds[0].categories[0].questions[0].isRevealed).toBe(false);
        });

        it('should return null for non-existent game', () => {
            const result = duplicateKuldvillakGame('non-existent');
            expect(result).toBeNull();
        });
    });

    describe('getKuldvillakGamesList', () => {
        it('should return empty array when no games', () => {
            const result = getKuldvillakGamesList();
            expect(result).toEqual([]);
        });

        it('should return metadata for all games', () => {
            saveKuldvillakGame(createTestGame({ id: 'game-1', name: 'Game 1' }));
            saveKuldvillakGame(createTestGame({ id: 'game-2', name: 'Game 2' }));

            const list = getKuldvillakGamesList();

            expect(list).toHaveLength(2);
            expect(list[0].teamCount).toBe(2);
            expect(list[0].roundCount).toBe(1);
        });
    });

    describe('Active Game', () => {
        it('should set and get active game ID', () => {
            setActiveKuldvillakGame('test-id');
            expect(getActiveKuldvillakGameId()).toBe('test-id');
        });

        it('should clear active game when set to null', () => {
            setActiveKuldvillakGame('test-id');
            setActiveKuldvillakGame(null);
            expect(getActiveKuldvillakGameId()).toBeNull();
        });
    });
});
