import { renderHook, act, waitFor } from '@testing-library/react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { useQuizLibrary } from '../../hooks/useQuizLibrary';
import type { Quiz } from '../../types';

const mockAuthFetch = vi.fn();

vi.mock('../../hooks/useAuthenticatedFetch', () => ({
  useAuthenticatedFetch: () => ({
    authFetch: mockAuthFetch,
    isAuthenticated: true,
  }),
}));

vi.mock('react-hot-toast', () => ({
  default: {
    success: vi.fn(),
    error: vi.fn(),
  },
}));

const createMockQuiz = (overrides?: Partial<Quiz>): Quiz => ({
  title: 'Test Quiz',
  questions: [
    {
      id: 'q1',
      text: 'What is 2+2?',
      timeLimit: 20,
      options: [
        { text: '3', isCorrect: false, shape: 'triangle', color: 'red' },
        { text: '4', isCorrect: true, shape: 'diamond', color: 'blue' },
        { text: '5', isCorrect: false, shape: 'circle', color: 'yellow' },
        { text: '6', isCorrect: false, shape: 'square', color: 'green' },
      ],
    },
  ],
  ...overrides,
});

describe('useQuizLibrary', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockAuthFetch.mockReset();
  });

  describe('fetchQuizzes', () => {
    it('fetches and stores quizzes', async () => {
      const mockQuizzes = [
        { id: '1', title: 'Quiz 1', source: 'manual', questionCount: 5, createdAt: '2024-01-01', updatedAt: '2024-01-01' },
        { id: '2', title: 'Quiz 2', source: 'ai_generated', questionCount: 10, createdAt: '2024-01-02', updatedAt: '2024-01-02' },
      ];
      mockAuthFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(mockQuizzes),
      });

      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.fetchQuizzes();
      });

      expect(result.current.quizzes).toEqual(mockQuizzes);
      expect(result.current.loading).toBe(false);
      expect(result.current.error).toBeNull();
    });

    it('sets loading to true during fetch', async () => {
      let resolvePromise: (value: unknown) => void;
      const pendingPromise = new Promise((resolve) => {
        resolvePromise = resolve;
      });
      mockAuthFetch.mockReturnValueOnce(pendingPromise);

      const { result } = renderHook(() => useQuizLibrary());

      act(() => {
        result.current.fetchQuizzes();
      });

      await waitFor(() => {
        expect(result.current.loading).toBe(true);
      });

      await act(async () => {
        resolvePromise!({ ok: true, json: () => Promise.resolve([]) });
      });

      await waitFor(() => {
        expect(result.current.loading).toBe(false);
      });
    });

    it('handles 500 server error', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 500,
      });

      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.fetchQuizzes();
      });

      expect(result.current.error).toBe('Server error. Please try again.');
      expect(result.current.loading).toBe(false);
    });

    it('handles generic error', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 400,
      });

      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.fetchQuizzes();
      });

      expect(result.current.error).toBe('Failed to load your quizzes.');
    });
  });

  describe('loadQuiz', () => {
    it('loads and returns a quiz', async () => {
      const mockQuiz = {
        id: 'quiz-123',
        title: 'Loaded Quiz',
        source: 'manual',
        questions: [],
        createdAt: '2024-01-01',
        updatedAt: '2024-01-01',
      };
      mockAuthFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(mockQuiz),
      });

      const { result } = renderHook(() => useQuizLibrary());

      let loadedQuiz;
      await act(async () => {
        loadedQuiz = await result.current.loadQuiz('quiz-123');
      });

      expect(loadedQuiz).toEqual(mockQuiz);
      expect(mockAuthFetch).toHaveBeenCalledWith('/api/quizzes/quiz-123');
    });

    it('sets and clears loadingQuizId', async () => {
      let resolvePromise: (value: unknown) => void;
      const pendingPromise = new Promise((resolve) => {
        resolvePromise = resolve;
      });
      mockAuthFetch.mockReturnValueOnce(pendingPromise);

      const { result } = renderHook(() => useQuizLibrary());

      act(() => {
        result.current.loadQuiz('quiz-123');
      });

      await waitFor(() => {
        expect(result.current.loadingQuizId).toBe('quiz-123');
      });

      await act(async () => {
        resolvePromise!({ ok: true, json: () => Promise.resolve({}) });
      });

      await waitFor(() => {
        expect(result.current.loadingQuizId).toBeNull();
      });
    });

    it('handles 404 not found', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 404,
      });

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.loadQuiz('non-existent');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Quiz not found. It may have been deleted.');
      }
      
      expect(result.current.loadingQuizId).toBeNull();
    });

    it('handles generic error', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 500,
      });

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.loadQuiz('quiz-123');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Failed to load quiz.');
      }
    });
  });

  describe('saveQuiz', () => {
    it('saves a quiz and returns the ID', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve({ id: 'new-quiz-id' }),
      });

      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz();

      let savedId;
      await act(async () => {
        savedId = await result.current.saveQuiz(quiz, 'manual');
      });

      expect(savedId).toBe('new-quiz-id');
      expect(result.current.saving).toBe(false);
    });

    it('sends correct request body for manual quiz', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve({ id: 'id' }),
      });

      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz({ title: 'Manual Quiz' });

      await act(async () => {
        await result.current.saveQuiz(quiz, 'manual');
      });

      const [, options] = mockAuthFetch.mock.calls[0];
      const body = JSON.parse(options.body);
      expect(body.title).toBe('Manual Quiz');
      expect(body.source).toBe('manual');
      expect(body.aiTopic).toBeUndefined();
    });

    it('sends aiTopic for AI generated quiz', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve({ id: 'id' }),
      });

      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz();

      await act(async () => {
        await result.current.saveQuiz(quiz, 'ai_generated', 'Science');
      });

      const [, options] = mockAuthFetch.mock.calls[0];
      const body = JSON.parse(options.body);
      expect(body.source).toBe('ai_generated');
      expect(body.aiTopic).toBe('Science');
    });

    it('includes gameConfig when present', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve({ id: 'id' }),
      });

      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz({
        config: {
          shuffleQuestions: true,
          shuffleAnswers: false,
          hostParticipates: true,
          randomNamesEnabled: false,
          streakBonusEnabled: false,
          streakThreshold: 3,
          streakMultiplier: 1.1,
          comebackBonusEnabled: false,
          comebackBonusPoints: 50,
          penaltyForWrongAnswer: false,
          penaltyPercent: 25,
          firstCorrectBonusEnabled: false,
          firstCorrectBonusPoints: 50,
        },
      });

      await act(async () => {
        await result.current.saveQuiz(quiz, 'manual');
      });

      const [, options] = mockAuthFetch.mock.calls[0];
      const body = JSON.parse(options.body);
      expect(body.gameConfig.shuffleQuestions).toBe(true);
    });

    it('rejects quiz without title', async () => {
      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz({ title: '' });

      try {
        await act(async () => {
          await result.current.saveQuiz(quiz, 'manual');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Quiz must have a title');
      }

      expect(mockAuthFetch).not.toHaveBeenCalled();
    });

    it('rejects quiz with whitespace-only title', async () => {
      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz({ title: '   ' });

      try {
        await act(async () => {
          await result.current.saveQuiz(quiz, 'manual');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Quiz must have a title');
      }
    });

    it('rejects quiz without questions', async () => {
      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz({ questions: [] });

      try {
        await act(async () => {
          await result.current.saveQuiz(quiz, 'manual');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Quiz must have at least one question');
      }
    });

    it('rejects quiz with question without text', async () => {
      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz({
        questions: [{
          id: 'q1',
          text: '',
          timeLimit: 20,
          options: [
            { text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
            { text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
          ],
        }],
      });

      try {
        await act(async () => {
          await result.current.saveQuiz(quiz, 'manual');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('All questions must have text');
      }
    });

    it('rejects question with less than 2 options', async () => {
      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz({
        questions: [{
          id: 'q1',
          text: 'Question?',
          timeLimit: 20,
          options: [
            { text: 'A', isCorrect: true, shape: 'triangle', color: 'red' },
          ],
        }],
      });

      try {
        await act(async () => {
          await result.current.saveQuiz(quiz, 'manual');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Each question must have at least 2 options');
      }
    });

    it('rejects question without correct answer', async () => {
      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz({
        questions: [{
          id: 'q1',
          text: 'Question?',
          timeLimit: 20,
          options: [
            { text: 'A', isCorrect: false, shape: 'triangle', color: 'red' },
            { text: 'B', isCorrect: false, shape: 'diamond', color: 'blue' },
          ],
        }],
      });

      try {
        await act(async () => {
          await result.current.saveQuiz(quiz, 'manual');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Each question must have a correct answer');
      }
    });

    it('prevents double save when already saving', async () => {
      let resolveFirstSave: (value: unknown) => void;
      const firstSavePromise = new Promise((resolve) => {
        resolveFirstSave = resolve;
      });
      mockAuthFetch.mockReturnValueOnce(firstSavePromise);

      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz();

      let firstSaveResult: Promise<string>;
      act(() => {
        firstSaveResult = result.current.saveQuiz(quiz, 'manual');
      });

      await waitFor(() => {
        expect(result.current.saving).toBe(true);
      });

      let secondSaveError: Error | null = null;
      await act(async () => {
        try {
          await result.current.saveQuiz(quiz, 'manual');
        } catch (e) {
          secondSaveError = e as Error;
        }
      });

      expect(secondSaveError).not.toBeNull();
      expect(secondSaveError!.message).toBe('Save already in progress');
      expect(mockAuthFetch).toHaveBeenCalledTimes(1);

      await act(async () => {
        resolveFirstSave!({ ok: true, json: () => Promise.resolve({ id: 'test-id' }) });
        await firstSaveResult!;
      });

      expect(result.current.saving).toBe(false);
    });

    it('handles 400 validation error', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 400,
      });

      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz();

      try {
        await act(async () => {
          await result.current.saveQuiz(quiz, 'manual');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Invalid quiz data. Please check and try again.');
      }
    });

    it('handles generic server error', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 500,
      });

      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz();

      try {
        await act(async () => {
          await result.current.saveQuiz(quiz, 'manual');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Failed to save quiz.');
      }
    });
  });

  describe('deleteQuiz', () => {
    it('handles 404 not found', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 404,
      });

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.deleteQuiz('non-existent');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Quiz not found.');
      }
    });

    it('handles generic server error', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 500,
      });

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.deleteQuiz('quiz-123');
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Failed to delete quiz.');
      }
    });
  });

  describe('updateQuizConfig', () => {
    it('throws error on failure', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 500,
      });

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.updateQuizConfig('quiz-123', {} as any);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Failed to update config');
      }
    });
  });

  describe('updateQuiz', () => {
    it('handles generic server error', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 500,
      });

      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz();

      try {
        await act(async () => {
          await result.current.updateQuiz('quiz-123', quiz);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Failed to update quiz.');
      }
    });

    it('handles empty quiz ID', async () => {
      mockAuthFetch.mockResolvedValueOnce({
        ok: false,
        status: 404,
      });

      const { result } = renderHook(() => useQuizLibrary());
      const quiz = createMockQuiz();

      try {
        await act(async () => {
          await result.current.updateQuiz('', quiz);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Quiz not found.');
      }
    });
  });

  describe('exportQuizzes', () => {
    let mockCreateObjectURL: ReturnType<typeof vi.fn>;
    let mockRevokeObjectURL: ReturnType<typeof vi.fn>;
    let mockClick: ReturnType<typeof vi.fn>;
    let capturedBlob: Blob | null = null;
    let originalCreateElement: typeof document.createElement;
    let originalCreateObjectURL: typeof URL.createObjectURL;
    let originalRevokeObjectURL: typeof URL.revokeObjectURL;

    beforeEach(() => {
      capturedBlob = null;
      mockCreateObjectURL = vi.fn((blob: Blob) => {
        capturedBlob = blob;
        return 'blob:test-url';
      });
      mockRevokeObjectURL = vi.fn();
      mockClick = vi.fn();

      originalCreateObjectURL = global.URL.createObjectURL;
      originalRevokeObjectURL = global.URL.revokeObjectURL;
      global.URL.createObjectURL = mockCreateObjectURL as typeof URL.createObjectURL;
      global.URL.revokeObjectURL = mockRevokeObjectURL as typeof URL.revokeObjectURL;
      
      originalCreateElement = document.createElement.bind(document);
      vi.spyOn(document, 'createElement').mockImplementation((tag) => {
        if (tag === 'a') {
          return {
            href: '',
            download: '',
            click: mockClick,
          } as unknown as HTMLAnchorElement;
        }
        return originalCreateElement(tag);
      });
      
      vi.spyOn(document.body, 'appendChild').mockImplementation((node: Node) => node);
      vi.spyOn(document.body, 'removeChild').mockImplementation((node: Node) => node);
    });

    afterEach(() => {
      global.URL.createObjectURL = originalCreateObjectURL;
      global.URL.revokeObjectURL = originalRevokeObjectURL;
      vi.restoreAllMocks();
    });

    it('exports selected quizzes as JSON file', async () => {
      const mockQuizData = {
        id: 'quiz-1',
        title: 'Test Quiz',
        source: 'manual',
        questions: [
          { id: 'q1', text: 'Question 1', timeLimit: 20, options: [] },
        ],
      };

      mockAuthFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(mockQuizData),
      });

      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.exportQuizzes(['quiz-1']);
      });

      expect(mockAuthFetch).toHaveBeenCalledWith('/api/quizzes/quiz-1');
      expect(mockCreateObjectURL).toHaveBeenCalled();
      expect(mockClick).toHaveBeenCalled();
      expect(mockRevokeObjectURL).toHaveBeenCalledWith('blob:test-url');
      expect(result.current.exporting).toBe(false);
    });

    it('exports multiple quizzes', async () => {
      mockAuthFetch
        .mockResolvedValueOnce({
          ok: true,
          json: () => Promise.resolve({ id: 'quiz-1', title: 'Quiz 1', source: 'manual', questions: [] }),
        })
        .mockResolvedValueOnce({
          ok: true,
          json: () => Promise.resolve({ id: 'quiz-2', title: 'Quiz 2', source: 'ai_generated', aiTopic: 'Science', questions: [] }),
        });

      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.exportQuizzes(['quiz-1', 'quiz-2']);
      });

      expect(mockAuthFetch).toHaveBeenCalledTimes(2);
      expect(mockCreateObjectURL).toHaveBeenCalled();
    });

    it('sets exporting to true during export', async () => {
      let resolvePromise: (value: unknown) => void;
      const pendingPromise = new Promise((resolve) => {
        resolvePromise = resolve;
      });
      mockAuthFetch.mockReturnValueOnce(pendingPromise);

      const { result } = renderHook(() => useQuizLibrary());

      act(() => {
        result.current.exportQuizzes(['quiz-1']);
      });

      await waitFor(() => {
        expect(result.current.exporting).toBe(true);
      });

      await act(async () => {
        resolvePromise!({ ok: true, json: () => Promise.resolve({ id: 'quiz-1', title: 'Q', source: 'manual', questions: [] }) });
      });

      await waitFor(() => {
        expect(result.current.exporting).toBe(false);
      });
    });

    it('handles empty quiz IDs array', async () => {
      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.exportQuizzes([]);
      });

      expect(mockAuthFetch).not.toHaveBeenCalled();
      expect(mockCreateObjectURL).not.toHaveBeenCalled();
    });

    it('skips quizzes that fail to load', async () => {
      mockAuthFetch
        .mockResolvedValueOnce({ ok: false, status: 404 })
        .mockResolvedValueOnce({
          ok: true,
          json: () => Promise.resolve({ id: 'quiz-2', title: 'Quiz 2', source: 'manual', questions: [] }),
        });

      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.exportQuizzes(['quiz-1', 'quiz-2']);
      });

      expect(mockCreateObjectURL).toHaveBeenCalled();
      expect(capturedBlob).toBeInstanceOf(Blob);
    });

    it('handles network error during export', async () => {
      mockAuthFetch.mockRejectedValueOnce(new Error('Network error'));

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.exportQuizzes(['quiz-1']);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Network error');
      }

      expect(result.current.exporting).toBe(false);
    });

it('creates blob with correct mime type', async () => {
      const mockQuizData = {
        id: 'quiz-1',
        title: 'Test Quiz',
        source: 'ai_generated',
        aiTopic: 'History',
        gameConfig: { shuffleQuestions: true },
        questions: [
          {
            id: 'q1',
            text: 'What year?',
            timeLimit: 30,
            options: [
              { text: '1990', isCorrect: false, shape: 'triangle', color: 'red' },
              { text: '2000', isCorrect: true, shape: 'diamond', color: 'blue' },
            ],
          },
        ],
      };

      mockAuthFetch.mockResolvedValueOnce({
        ok: true,
        json: () => Promise.resolve(mockQuizData),
      });

      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.exportQuizzes(['quiz-1']);
      });

      expect(capturedBlob).not.toBeNull();
      expect(capturedBlob!.type).toBe('application/json');
    });
  });

  describe('parseImportFile', () => {
    const originalText = File.prototype.text;
    
    beforeEach(() => {
      // JSDOM doesn't implement File.prototype.text, so define it using FileReader
      File.prototype.text = function() {
        return new Promise((resolve, reject) => {
          const reader = new FileReader();
          reader.onload = () => resolve(reader.result as string);
          reader.onerror = () => reject(reader.error);
          reader.readAsText(this);
        });
      };
    });

    afterEach(() => {
      File.prototype.text = originalText;
    });

    it('parses valid export file', async () => {
      const validExportData = {
        version: 1,
        exportedAt: '2024-01-01T00:00:00.000Z',
        quizzes: [
          { title: 'Quiz 1', source: 'manual', questions: [] },
        ],
      };

      const file = new File(
        [JSON.stringify(validExportData)],
        'export.json',
        { type: 'application/json' }
      );

      const { result } = renderHook(() => useQuizLibrary());

      let parsed;
      await act(async () => {
        parsed = await result.current.parseImportFile(file);
      });

      expect(parsed).toEqual(validExportData);
    });

    it('rejects file without version field', async () => {
      const invalidData = {
        exportedAt: '2024-01-01T00:00:00.000Z',
        quizzes: [],
      };

      const file = new File(
        [JSON.stringify(invalidData)],
        'export.json',
        { type: 'application/json' }
      );

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.parseImportFile(file);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Invalid export file format');
      }
    });

    it('rejects file without quizzes array', async () => {
      const invalidData = {
        version: 1,
        exportedAt: '2024-01-01T00:00:00.000Z',
      };

      const file = new File(
        [JSON.stringify(invalidData)],
        'export.json',
        { type: 'application/json' }
      );

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.parseImportFile(file);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Invalid export file format');
      }
    });

    it('rejects file with quizzes as non-array', async () => {
      const invalidData = {
        version: 1,
        exportedAt: '2024-01-01T00:00:00.000Z',
        quizzes: 'not-an-array',
      };

      const file = new File(
        [JSON.stringify(invalidData)],
        'export.json',
        { type: 'application/json' }
      );

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.parseImportFile(file);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Invalid export file format');
      }
    });

    it('rejects invalid JSON', async () => {
      const file = new File(
        ['not valid json {'],
        'export.json',
        { type: 'application/json' }
      );

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.parseImportFile(file);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect(e).toBeInstanceOf(SyntaxError);
      }
    });

    it('handles empty file', async () => {
      const file = new File(
        [''],
        'export.json',
        { type: 'application/json' }
      );

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.parseImportFile(file);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect(e).toBeInstanceOf(SyntaxError);
      }
    });
  });

  describe('importQuizzes', () => {
    it('imports single quiz successfully', async () => {
      mockAuthFetch
        .mockResolvedValueOnce({
          ok: true,
          json: () => Promise.resolve({ id: 'new-quiz-1' }),
        })
        .mockResolvedValueOnce({
          ok: true,
          json: () => Promise.resolve([]),
        });

      const { result } = renderHook(() => useQuizLibrary());

      const quizzesToImport = [
        {
          title: 'Imported Quiz',
          source: 'manual' as const,
          questions: [
            {
              id: 'q1',
              text: 'Question?',
              timeLimit: 20,
              options: [
                { text: 'A', isCorrect: true, shape: 'triangle' as const, color: 'red' as const },
                { text: 'B', isCorrect: false, shape: 'diamond' as const, color: 'blue' as const },
              ],
            },
          ],
        },
      ];

      await act(async () => {
        await result.current.importQuizzes(quizzesToImport);
      });

      expect(mockAuthFetch).toHaveBeenCalledWith('/api/quizzes', expect.objectContaining({
        method: 'POST',
      }));
      expect(result.current.importing).toBe(false);
    });

    it('imports multiple quizzes sequentially', async () => {
      mockAuthFetch
        .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ id: 'q1' }) })
        .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ id: 'q2' }) })
        .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve([]) });

      const { result } = renderHook(() => useQuizLibrary());

      const quizzesToImport = [
        { title: 'Quiz 1', source: 'manual' as const, questions: createMockQuiz().questions },
        { title: 'Quiz 2', source: 'ai_generated' as const, aiTopic: 'Science', questions: createMockQuiz().questions },
      ];

      await act(async () => {
        await result.current.importQuizzes(quizzesToImport);
      });

      expect(mockAuthFetch).toHaveBeenCalledTimes(3);
    });

    it('sets importing to true during import', async () => {
      let resolvePromise: (value: unknown) => void;
      const pendingPromise = new Promise((resolve) => {
        resolvePromise = resolve;
      });
      mockAuthFetch.mockReturnValueOnce(pendingPromise);

      const { result } = renderHook(() => useQuizLibrary());

      act(() => {
        result.current.importQuizzes([
          { title: 'Quiz', source: 'manual', questions: createMockQuiz().questions },
        ]);
      });

      await waitFor(() => {
        expect(result.current.importing).toBe(true);
      });

      await act(async () => {
        resolvePromise!({ ok: true, json: () => Promise.resolve({ id: 'id' }) });
      });
    });

    it('handles empty quizzes array', async () => {
      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.importQuizzes([]);
      });

      expect(mockAuthFetch).not.toHaveBeenCalled();
    });

    it('reports partial success when some imports fail', async () => {
      mockAuthFetch
        .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ id: 'q1' }) })
        .mockResolvedValueOnce({ ok: false, status: 400 });

      const { result } = renderHook(() => useQuizLibrary());

      const quizzesToImport = [
        { title: 'Quiz 1', source: 'manual' as const, questions: createMockQuiz().questions },
        { title: 'Quiz 2', source: 'manual' as const, questions: createMockQuiz().questions },
      ];

      try {
        await act(async () => {
          await result.current.importQuizzes(quizzesToImport);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toContain('Invalid quiz data');
      }

      expect(result.current.importing).toBe(false);
    });

    it('refreshes quiz list after successful import', async () => {
      const mockQuizList = [{ id: 'q1', title: 'Quiz 1', source: 'manual', questionCount: 1, createdAt: '2024-01-01', updatedAt: '2024-01-01' }];
      
      mockAuthFetch
        .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ id: 'q1' }) })
        .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve(mockQuizList) });

      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.importQuizzes([
          { title: 'Quiz 1', source: 'manual', questions: createMockQuiz().questions },
        ]);
      });

      expect(mockAuthFetch).toHaveBeenLastCalledWith('/api/quizzes');
      expect(result.current.quizzes).toEqual(mockQuizList);
    });

    it('preserves aiTopic for AI-generated quizzes', async () => {
      mockAuthFetch
        .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ id: 'q1' }) })
        .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve([]) });

      const { result } = renderHook(() => useQuizLibrary());

      await act(async () => {
        await result.current.importQuizzes([
          { title: 'AI Quiz', source: 'ai_generated', aiTopic: 'Space', questions: createMockQuiz().questions },
        ]);
      });

      const [, options] = mockAuthFetch.mock.calls[0];
      const body = JSON.parse(options.body);
      expect(body.source).toBe('ai_generated');
      expect(body.aiTopic).toBe('Space');
    });

    it('preserves game config during import', async () => {
      mockAuthFetch
        .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ id: 'q1' }) })
        .mockResolvedValueOnce({ ok: true, json: () => Promise.resolve([]) });

      const { result } = renderHook(() => useQuizLibrary());

      const config = {
        shuffleQuestions: true,
        shuffleAnswers: true,
        hostParticipates: false,
        randomNamesEnabled: true,
        streakBonusEnabled: true,
        streakThreshold: 5,
        streakMultiplier: 1.5,
        comebackBonusEnabled: false,
        comebackBonusPoints: 100,
        penaltyForWrongAnswer: true,
        penaltyPercent: 10,
        firstCorrectBonusEnabled: true,
        firstCorrectBonusPoints: 25,
      };

      await act(async () => {
        await result.current.importQuizzes([
          { title: 'Quiz', source: 'manual', config, questions: createMockQuiz().questions },
        ]);
      });

      const [, options] = mockAuthFetch.mock.calls[0];
      const body = JSON.parse(options.body);
      expect(body.gameConfig).toEqual(config);
    });

    it('handles network error during import', async () => {
      mockAuthFetch.mockRejectedValueOnce(new Error('Network error'));

      const { result } = renderHook(() => useQuizLibrary());

      try {
        await act(async () => {
          await result.current.importQuizzes([
            { title: 'Quiz', source: 'manual', questions: createMockQuiz().questions },
          ]);
        });
        expect.fail('Should have thrown');
      } catch (e) {
        expect((e as Error).message).toBe('Network error');
      }

      expect(result.current.importing).toBe(false);
    });
  });
});
