import { describe, it, expect, beforeEach, afterEach } from "bun:test";

describe('Signin Migration Logic (Unit Tests)', () => {
	
	// Test the deduplication algorithm independently
	it('should correctly identify and remove duplicates keeping earliest', () => {
		// Mock completion data structure
		type MockCompletion = {
			id: string;
			anonymousId: string;
			date: string;
			guessCount: number;
			completedAt: Date;
		};

		// Test data: multiple completions on same date
		const allUserCompletions: MockCompletion[] = [
			{
				id: 'comp1',
				anonymousId: 'user123',
				date: '2024-01-01',
				guessCount: 4,
				completedAt: new Date('2024-01-01T08:00:00Z') // Earliest
			},
			{
				id: 'comp2', 
				anonymousId: 'user123',
				date: '2024-01-01',
				guessCount: 2,
				completedAt: new Date('2024-01-01T14:00:00Z') // Later
			},
			{
				id: 'comp3',
				anonymousId: 'user123',
				date: '2024-01-01',
				guessCount: 6,
				completedAt: new Date('2024-01-01T20:00:00Z') // Latest
			},
			{
				id: 'comp4',
				anonymousId: 'user123',
				date: '2024-01-02',
				guessCount: 3,
				completedAt: new Date('2024-01-02T09:00:00Z') // Unique date
			}
		];

		// Implement the deduplication logic from signin server action
		const dateGroups = new Map<string, MockCompletion[]>();
		for (const completion of allUserCompletions) {
			const date = completion.date;
			if (!dateGroups.has(date)) {
				dateGroups.set(date, []);
			}
			dateGroups.get(date)!.push(completion);
		}

		// Process dates with duplicates
		const duplicateIds: string[] = [];
		const keptEntries: MockCompletion[] = [];
		
		for (const [date, completions] of dateGroups) {
			if (completions.length > 1) {
				// Sort by completedAt timestamp (earliest first)
				completions.sort((a, b) => a.completedAt.getTime() - b.completedAt.getTime());
				
				// Keep the first (earliest), mark the rest for deletion
				const toKeep = completions[0];
				const toDelete = completions.slice(1);
				
				keptEntries.push(toKeep);
				duplicateIds.push(...toDelete.map(c => c.id));
			} else {
				// Single entry for this date, keep it
				keptEntries.push(completions[0]);
			}
		}

		// Verify the logic worked correctly
		expect(duplicateIds).toHaveLength(2); // comp2 and comp3 should be deleted
		expect(duplicateIds).toContain('comp2');
		expect(duplicateIds).toContain('comp3');
		expect(duplicateIds).not.toContain('comp1'); // comp1 should be kept (earliest)
		expect(duplicateIds).not.toContain('comp4'); // comp4 should be kept (unique date)

		// Verify kept entries
		expect(keptEntries).toHaveLength(2);
		
		// Check that the earliest entry for 2024-01-01 was kept
		const jan1Entry = keptEntries.find(e => e.date === '2024-01-01');
		expect(jan1Entry).toBeTruthy();
		expect(jan1Entry!.id).toBe('comp1'); // Earliest timestamp
		expect(jan1Entry!.guessCount).toBe(4);
		expect(jan1Entry!.completedAt.getTime()).toBe(new Date('2024-01-01T08:00:00Z').getTime());

		// Check that unique date entry was preserved
		const jan2Entry = keptEntries.find(e => e.date === '2024-01-02');
		expect(jan2Entry).toBeTruthy();
		expect(jan2Entry!.id).toBe('comp4');
	});

	it('should handle no duplicates correctly', () => {
		type MockCompletion = {
			id: string;
			anonymousId: string;
			date: string;
			guessCount: number;
			completedAt: Date;
		};

		// Test data: all unique dates
		const allUserCompletions: MockCompletion[] = [
			{
				id: 'comp1',
				anonymousId: 'user123',
				date: '2024-01-01',
				guessCount: 4,
				completedAt: new Date('2024-01-01T08:00:00Z')
			},
			{
				id: 'comp2',
				anonymousId: 'user123', 
				date: '2024-01-02',
				guessCount: 2,
				completedAt: new Date('2024-01-02T14:00:00Z')
			}
		];

		// Run deduplication logic
		const dateGroups = new Map<string, MockCompletion[]>();
		for (const completion of allUserCompletions) {
			if (!dateGroups.has(completion.date)) {
				dateGroups.set(completion.date, []);
			}
			dateGroups.get(completion.date)!.push(completion);
		}

		const duplicateIds: string[] = [];
		for (const [date, completions] of dateGroups) {
			if (completions.length > 1) {
				completions.sort((a, b) => a.completedAt.getTime() - b.completedAt.getTime());
				const toDelete = completions.slice(1);
				duplicateIds.push(...toDelete.map(c => c.id));
			}
		}

		// Should find no duplicates
		expect(duplicateIds).toHaveLength(0);
	});

	it('should handle edge case with same timestamp', () => {
		type MockCompletion = {
			id: string;
			anonymousId: string;
			date: string;
			guessCount: number;
			completedAt: Date;
		};

		// Edge case: same completion time (very unlikely but possible)
		const sameTime = new Date('2024-01-01T08:00:00Z');
		const allUserCompletions: MockCompletion[] = [
			{
				id: 'comp1',
				anonymousId: 'user123',
				date: '2024-01-01',
				guessCount: 3,
				completedAt: sameTime
			},
			{
				id: 'comp2',
				anonymousId: 'user123',
				date: '2024-01-01', 
				guessCount: 5,
				completedAt: sameTime
			}
		];

		// Run deduplication logic
		const dateGroups = new Map<string, MockCompletion[]>();
		for (const completion of allUserCompletions) {
			if (!dateGroups.has(completion.date)) {
				dateGroups.set(completion.date, []);
			}
			dateGroups.get(completion.date)!.push(completion);
		}

		const duplicateIds: string[] = [];
		for (const [date, completions] of dateGroups) {
			if (completions.length > 1) {
				completions.sort((a, b) => a.completedAt.getTime() - b.completedAt.getTime());
				const toDelete = completions.slice(1);
				duplicateIds.push(...toDelete.map(c => c.id));
			}
		}

		// Should still remove one duplicate (deterministically based on array order)
		expect(duplicateIds).toHaveLength(1);
		// Since they have the same timestamp, it keeps the first one in the sorted array
		expect(duplicateIds[0]).toBe('comp2'); // Second entry gets removed
	});

	it('should validate migration condition logic', () => {
		// Test the condition check that determines when migration should occur
		const testCases = [
			{ 
				anonymousId: 'device2-id',
				userId: 'device1-id',
				shouldMigrate: true,
				description: 'Different IDs should trigger migration'
			},
			{
				anonymousId: 'same-id',
				userId: 'same-id', 
				shouldMigrate: false,
				description: 'Same IDs should not trigger migration'
			},
			{
				anonymousId: null as any,
				userId: 'user-id',
				shouldMigrate: false,
				description: 'Null anonymous ID should not trigger migration'
			},
			{
				anonymousId: undefined as any,
				userId: 'user-id',
				shouldMigrate: false,
				description: 'Undefined anonymous ID should not trigger migration'
			},
			{
				anonymousId: '',
				userId: 'user-id', 
				shouldMigrate: false,
				description: 'Empty anonymous ID should not trigger migration'
			}
		];

		for (const testCase of testCases) {
			// This is the exact condition from signin/+page.server.ts
			const shouldMigrate = !!(testCase.anonymousId && testCase.anonymousId !== testCase.userId);
			
			expect(shouldMigrate).toBe(testCase.shouldMigrate);
		}
	});
});