import { describe, it, expect, beforeEach } from 'vitest';
import type { Quiz } from '../../types';
import { DEFAULT_GAME_CONFIG } from '../../types';

const DRAFT_QUIZ_KEY = 'kaboot_draft_quiz';

interface DraftQuiz {
  quiz: Quiz;
  topic?: string;
  sourceQuizId?: string;
}

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('Draft Quiz Persistence', () => {
  let storage: Map<string, string>;

  const getDraftQuiz = (): DraftQuiz | null => {
    try {
      const stored = storage.get(DRAFT_QUIZ_KEY);
      return stored ? JSON.parse(stored) : null;
    } catch {
      return null;
    }
  };

  const storeDraftQuiz = (draft: DraftQuiz) => {
    storage.set(DRAFT_QUIZ_KEY, JSON.stringify(draft));
  };

  const clearDraftQuiz = () => {
    storage.delete(DRAFT_QUIZ_KEY);
  };

  beforeEach(() => {
    storage = new Map<string, string>();
  });

  describe('Draft Storage Operations', () => {
    it('should store a draft quiz', () => {
      const quiz = createMockQuiz();
      storeDraftQuiz({ quiz, topic: 'Math' });

      expect(storage.has(DRAFT_QUIZ_KEY)).toBe(true);
      const stored = getDraftQuiz();
      expect(stored?.quiz.title).toBe('Test Quiz');
      expect(stored?.topic).toBe('Math');
    });

    it('should store draft quiz with sourceQuizId for library quizzes', () => {
      const quiz = createMockQuiz();
      storeDraftQuiz({ quiz, sourceQuizId: 'quiz-abc-123' });

      const stored = getDraftQuiz();
      expect(stored?.sourceQuizId).toBe('quiz-abc-123');
      expect(stored?.topic).toBeUndefined();
    });

    it('should retrieve null when no draft exists', () => {
      const stored = getDraftQuiz();
      expect(stored).toBeNull();
    });

    it('should clear draft quiz', () => {
      const quiz = createMockQuiz();
      storeDraftQuiz({ quiz });

      clearDraftQuiz();

      expect(storage.has(DRAFT_QUIZ_KEY)).toBe(false);
      expect(getDraftQuiz()).toBeNull();
    });

    it('should overwrite existing draft', () => {
      const quiz1 = createMockQuiz({ title: 'First Quiz' });
      const quiz2 = createMockQuiz({ title: 'Second Quiz' });

      storeDraftQuiz({ quiz: quiz1, topic: 'Topic 1' });
      storeDraftQuiz({ quiz: quiz2, topic: 'Topic 2' });

      const stored = getDraftQuiz();
      expect(stored?.quiz.title).toBe('Second Quiz');
      expect(stored?.topic).toBe('Topic 2');
    });

    it('should preserve quiz config in draft', () => {
      const quizWithConfig = createMockQuiz({
        config: {
          ...DEFAULT_GAME_CONFIG,
          shuffleQuestions: true,
          hostParticipates: false,
        },
      });

      storeDraftQuiz({ quiz: quizWithConfig });

      const stored = getDraftQuiz();
      expect(stored?.quiz.config?.shuffleQuestions).toBe(true);
      expect(stored?.quiz.config?.hostParticipates).toBe(false);
    });
  });

  describe('URL Path Generation for Editing', () => {
    const getEditTargetPath = (sourceQuizId: string | null): string => {
      return sourceQuizId ? `/edit/${sourceQuizId}` : '/edit/draft';
    };

    it('should return /edit/draft when no sourceQuizId', () => {
      expect(getEditTargetPath(null)).toBe('/edit/draft');
    });

    it('should return /edit/:quizId when sourceQuizId exists', () => {
      expect(getEditTargetPath('quiz-123')).toBe('/edit/quiz-123');
    });

    it('should handle UUID-style quiz IDs', () => {
      expect(getEditTargetPath('a1b2c3d4-e5f6-7890-abcd-ef1234567890'))
        .toBe('/edit/a1b2c3d4-e5f6-7890-abcd-ef1234567890');
    });

    it('should handle short alphanumeric IDs', () => {
      expect(getEditTargetPath('abc123')).toBe('/edit/abc123');
    });
  });

  describe('URL Initialization for Edit Routes', () => {
    interface InitResult {
      action: string;
      quiz?: Quiz;
      sourceQuizId?: string | null;
      topic?: string;
    }

    const simulateEditUrlInit = (
      path: string,
      draftQuiz: DraftQuiz | null
    ): InitResult => {
      if (path === '/edit/draft') {
        if (draftQuiz) {
          return {
            action: 'restoreDraft',
            quiz: draftQuiz.quiz,
            sourceQuizId: null,
            topic: draftQuiz.topic,
          };
        }
        return { action: 'navigateHome' };
      }

      const editMatch = path.match(/^\/edit\/([a-zA-Z0-9-]+)$/);
      if (editMatch) {
        const quizId = editMatch[1];
        if (draftQuiz && draftQuiz.sourceQuizId === quizId) {
          return {
            action: 'restoreLibraryQuiz',
            quiz: draftQuiz.quiz,
            sourceQuizId: quizId,
          };
        }
        return { action: 'navigateHome' };
      }

      return { action: 'noMatch' };
    };

    describe('/edit/draft URL', () => {
      it('should restore draft when draft exists in storage', () => {
        const quiz = createMockQuiz();
        const draft: DraftQuiz = { quiz, topic: 'Science' };

        const result = simulateEditUrlInit('/edit/draft', draft);

        expect(result.action).toBe('restoreDraft');
        expect(result.quiz?.title).toBe('Test Quiz');
        expect(result.sourceQuizId).toBeNull();
        expect(result.topic).toBe('Science');
      });

      it('should navigate home when no draft exists', () => {
        const result = simulateEditUrlInit('/edit/draft', null);

        expect(result.action).toBe('navigateHome');
      });

      it('should restore draft without topic (manual creation)', () => {
        const quiz = createMockQuiz();
        const draft: DraftQuiz = { quiz };

        const result = simulateEditUrlInit('/edit/draft', draft);

        expect(result.action).toBe('restoreDraft');
        expect(result.topic).toBeUndefined();
      });
    });

    describe('/edit/:quizId URL', () => {
      it('should restore library quiz when quizId matches', () => {
        const quiz = createMockQuiz();
        const draft: DraftQuiz = { quiz, sourceQuizId: 'quiz-456' };

        const result = simulateEditUrlInit('/edit/quiz-456', draft);

        expect(result.action).toBe('restoreLibraryQuiz');
        expect(result.quiz?.title).toBe('Test Quiz');
        expect(result.sourceQuizId).toBe('quiz-456');
      });

      it('should navigate home when quizId does not match stored draft', () => {
        const quiz = createMockQuiz();
        const draft: DraftQuiz = { quiz, sourceQuizId: 'quiz-789' };

        const result = simulateEditUrlInit('/edit/quiz-456', draft);

        expect(result.action).toBe('navigateHome');
      });

      it('should navigate home when no draft exists', () => {
        const result = simulateEditUrlInit('/edit/quiz-456', null);

        expect(result.action).toBe('navigateHome');
      });

      it('should navigate home when draft has no sourceQuizId', () => {
        const quiz = createMockQuiz();
        const draft: DraftQuiz = { quiz, topic: 'AI Generated' };

        const result = simulateEditUrlInit('/edit/quiz-456', draft);

        expect(result.action).toBe('navigateHome');
      });
    });

    describe('URL pattern matching', () => {
      it('should match UUID-style quiz IDs', () => {
        const quiz = createMockQuiz();
        const draft: DraftQuiz = { quiz, sourceQuizId: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890' };

        const result = simulateEditUrlInit('/edit/a1b2c3d4-e5f6-7890-abcd-ef1234567890', draft);

        expect(result.action).toBe('restoreLibraryQuiz');
      });

      it('should match alphanumeric IDs', () => {
        const quiz = createMockQuiz();
        const draft: DraftQuiz = { quiz, sourceQuizId: 'abc123XYZ' };

        const result = simulateEditUrlInit('/edit/abc123XYZ', draft);

        expect(result.action).toBe('restoreLibraryQuiz');
      });

      it('should not match IDs with special characters', () => {
        const quiz = createMockQuiz();
        const draft: DraftQuiz = { quiz, sourceQuizId: 'quiz@123' };

        const result = simulateEditUrlInit('/edit/quiz@123', draft);

        expect(result.action).toBe('noMatch');
      });

      it('should not match /edit without ID', () => {
        const quiz = createMockQuiz();
        const draft: DraftQuiz = { quiz };

        const result = simulateEditUrlInit('/edit', draft);

        expect(result.action).toBe('noMatch');
      });

      it('should not match /edit/ with trailing slash only', () => {
        const quiz = createMockQuiz();
        const draft: DraftQuiz = { quiz };

        const result = simulateEditUrlInit('/edit/', draft);

        expect(result.action).toBe('noMatch');
      });
    });
  });

  describe('Draft Lifecycle Operations', () => {
    describe('loadSavedQuiz (library quiz)', () => {
      it('should store quiz with sourceQuizId when loading from library', () => {
        const quiz = createMockQuiz({ title: 'Library Quiz' });
        const quizId = 'lib-quiz-123';

        storeDraftQuiz({ quiz, sourceQuizId: quizId });

        const stored = getDraftQuiz();
        expect(stored?.quiz.title).toBe('Library Quiz');
        expect(stored?.sourceQuizId).toBe(quizId);
        expect(stored?.topic).toBeUndefined();
      });
    });

    describe('startQuizGen (AI generated quiz)', () => {
      it('should store quiz with topic when AI generates quiz', () => {
        const quiz = createMockQuiz({ title: 'AI Quiz' });
        const topic = 'Ancient History';

        storeDraftQuiz({ quiz, topic });

        const stored = getDraftQuiz();
        expect(stored?.quiz.title).toBe('AI Quiz');
        expect(stored?.topic).toBe(topic);
        expect(stored?.sourceQuizId).toBeUndefined();
      });

      it('should store quiz with file names as topic', () => {
        const quiz = createMockQuiz();
        const topic = 'document1.pdf, document2.pdf';

        storeDraftQuiz({ quiz, topic });

        const stored = getDraftQuiz();
        expect(stored?.topic).toBe('document1.pdf, document2.pdf');
      });
    });

    describe('updateQuizFromEditor', () => {
      it('should update stored draft when quiz is edited', () => {
        const originalQuiz = createMockQuiz({ title: 'Original' });
        storeDraftQuiz({ quiz: originalQuiz, topic: 'Topic' });

        const updatedQuiz = createMockQuiz({ title: 'Updated' });
        const currentDraft = getDraftQuiz();
        storeDraftQuiz({
          quiz: updatedQuiz,
          topic: currentDraft?.topic,
          sourceQuizId: currentDraft?.sourceQuizId,
        });

        const stored = getDraftQuiz();
        expect(stored?.quiz.title).toBe('Updated');
        expect(stored?.topic).toBe('Topic');
      });

      it('should preserve sourceQuizId when updating library quiz', () => {
        const originalQuiz = createMockQuiz({ title: 'Library Original' });
        storeDraftQuiz({ quiz: originalQuiz, sourceQuizId: 'lib-123' });

        const updatedQuiz = createMockQuiz({ title: 'Library Updated' });
        const currentDraft = getDraftQuiz();
        storeDraftQuiz({
          quiz: updatedQuiz,
          topic: currentDraft?.topic,
          sourceQuizId: currentDraft?.sourceQuizId,
        });

        const stored = getDraftQuiz();
        expect(stored?.quiz.title).toBe('Library Updated');
        expect(stored?.sourceQuizId).toBe('lib-123');
      });
    });

    describe('startGameFromEditor', () => {
      it('should clear draft when starting game', () => {
        const quiz = createMockQuiz();
        storeDraftQuiz({ quiz, topic: 'Test' });

        expect(getDraftQuiz()).not.toBeNull();

        clearDraftQuiz();

        expect(getDraftQuiz()).toBeNull();
      });
    });

    describe('backFromEditor', () => {
      it('should clear draft when going back from editor', () => {
        const quiz = createMockQuiz();
        storeDraftQuiz({ quiz, sourceQuizId: 'lib-456' });

        expect(getDraftQuiz()).not.toBeNull();

        clearDraftQuiz();

        expect(getDraftQuiz()).toBeNull();
      });
    });
  });

  describe('Non-Happy Path Scenarios', () => {
    describe('Corrupted storage', () => {
      it('should return null for corrupted JSON', () => {
        storage.set(DRAFT_QUIZ_KEY, 'not valid json {{{');

        const stored = getDraftQuiz();
        expect(stored).toBeNull();
      });

      it('should return null for empty string', () => {
        storage.set(DRAFT_QUIZ_KEY, '');

        const stored = getDraftQuiz();
        expect(stored).toBeNull();
      });

      it('should handle storage with wrong structure gracefully', () => {
        storage.set(DRAFT_QUIZ_KEY, JSON.stringify({ wrong: 'structure' }));

        const stored = getDraftQuiz();
        expect(stored).not.toBeNull();
        expect(stored?.quiz).toBeUndefined();
      });
    });

    describe('Edge cases', () => {
      it('should handle quiz with empty questions array', () => {
        const quiz = createMockQuiz({ questions: [] });
        storeDraftQuiz({ quiz });

        const stored = getDraftQuiz();
        expect(stored?.quiz.questions).toHaveLength(0);
      });

      it('should handle quiz with empty title', () => {
        const quiz = createMockQuiz({ title: '' });
        storeDraftQuiz({ quiz });

        const stored = getDraftQuiz();
        expect(stored?.quiz.title).toBe('');
      });

      it('should handle empty topic string', () => {
        const quiz = createMockQuiz();
        storeDraftQuiz({ quiz, topic: '' });

        const stored = getDraftQuiz();
        expect(stored?.topic).toBe('');
      });

      it('should handle very long quiz content', () => {
        const longText = 'A'.repeat(10000);
        const quiz = createMockQuiz({
          title: longText,
          questions: Array(100).fill(null).map((_, i) => ({
            id: `q${i}`,
            text: longText,
            timeLimit: 20,
            options: [
              { text: longText, isCorrect: true, shape: 'triangle' as const, color: 'red' as const },
            ],
          })),
        });

        storeDraftQuiz({ quiz });

        const stored = getDraftQuiz();
        expect(stored?.quiz.title).toBe(longText);
        expect(stored?.quiz.questions).toHaveLength(100);
      });
    });

    describe('Stale draft detection', () => {
      it('should detect when URL quizId does not match stored sourceQuizId', () => {
        const quiz = createMockQuiz();
        storeDraftQuiz({ quiz, sourceQuizId: 'old-quiz-id' });

        const draft = getDraftQuiz();
        const urlQuizId = 'new-quiz-id';

        const isStale = draft?.sourceQuizId !== urlQuizId;
        expect(isStale).toBe(true);
      });

      it('should detect when accessing /edit/:id but draft is for AI quiz (no sourceQuizId)', () => {
        const quiz = createMockQuiz();
        storeDraftQuiz({ quiz, topic: 'AI Generated' });

        const draft = getDraftQuiz();
        const urlQuizId = 'some-quiz-id';

        const canRestore = draft?.sourceQuizId === urlQuizId;
        expect(canRestore).toBe(false);
      });

      it('should detect when accessing /edit/draft but draft has sourceQuizId', () => {
        const quiz = createMockQuiz();
        storeDraftQuiz({ quiz, sourceQuizId: 'lib-quiz' });

        const draft = getDraftQuiz();

        const isDraftRoute = true;
        const hasSourceId = !!draft?.sourceQuizId;

        expect(hasSourceId).toBe(true);
      });
    });

    describe('Multiple browser tabs', () => {
      it('should overwrite draft from another tab', () => {
        const quiz1 = createMockQuiz({ title: 'Tab 1 Quiz' });
        storeDraftQuiz({ quiz: quiz1, topic: 'Tab 1' });

        const quiz2 = createMockQuiz({ title: 'Tab 2 Quiz' });
        storeDraftQuiz({ quiz: quiz2, topic: 'Tab 2' });

        const stored = getDraftQuiz();
        expect(stored?.quiz.title).toBe('Tab 2 Quiz');
      });
    });

    describe('Page refresh timing', () => {
      it('should restore draft immediately on page load', () => {
        const quiz = createMockQuiz({ title: 'Refreshed Quiz' });
        storeDraftQuiz({ quiz, topic: 'Refresh Test' });

        const stored = getDraftQuiz();
        expect(stored).not.toBeNull();
        expect(stored?.quiz.title).toBe('Refreshed Quiz');
      });

      it('should handle refresh when storage was cleared externally', () => {
        const quiz = createMockQuiz();
        storeDraftQuiz({ quiz });

        storage.clear();

        const stored = getDraftQuiz();
        expect(stored).toBeNull();
      });
    });
  });

  describe('Integration: Full Edit Flow', () => {
    it('should support full AI quiz edit flow: generate -> edit -> refresh -> continue', () => {
      const generatedQuiz = createMockQuiz({ title: 'AI Generated Quiz' });
      storeDraftQuiz({ quiz: generatedQuiz, topic: 'Physics' });

      const afterRefresh = getDraftQuiz();
      expect(afterRefresh?.quiz.title).toBe('AI Generated Quiz');
      expect(afterRefresh?.topic).toBe('Physics');
      expect(afterRefresh?.sourceQuizId).toBeUndefined();

      const editedQuiz = createMockQuiz({ title: 'AI Generated Quiz - Edited' });
      storeDraftQuiz({
        quiz: editedQuiz,
        topic: afterRefresh?.topic,
        sourceQuizId: afterRefresh?.sourceQuizId,
      });

      const afterEdit = getDraftQuiz();
      expect(afterEdit?.quiz.title).toBe('AI Generated Quiz - Edited');

      clearDraftQuiz();
      expect(getDraftQuiz()).toBeNull();
    });

    it('should support full library quiz edit flow: load -> edit -> refresh -> continue', () => {
      const libraryQuiz = createMockQuiz({ title: 'My Saved Quiz' });
      const quizId = 'saved-quiz-abc';
      storeDraftQuiz({ quiz: libraryQuiz, sourceQuizId: quizId });

      const afterRefresh = getDraftQuiz();
      expect(afterRefresh?.quiz.title).toBe('My Saved Quiz');
      expect(afterRefresh?.sourceQuizId).toBe(quizId);

      const editedQuiz = createMockQuiz({ title: 'My Saved Quiz - Updated' });
      storeDraftQuiz({
        quiz: editedQuiz,
        topic: afterRefresh?.topic,
        sourceQuizId: afterRefresh?.sourceQuizId,
      });

      const afterEdit = getDraftQuiz();
      expect(afterEdit?.quiz.title).toBe('My Saved Quiz - Updated');
      expect(afterEdit?.sourceQuizId).toBe(quizId);

      clearDraftQuiz();
      expect(getDraftQuiz()).toBeNull();
    });
  });
});

describe('Edit Route Authentication Protection', () => {
  interface AuthState {
    isLoading: boolean;
    isAuthenticated: boolean;
  }

  const shouldRedirectToAuth = (
    pathname: string,
    auth: AuthState
  ): { redirect: boolean; action?: 'signin' | 'wait' | 'allow' } => {
    const isLibraryQuizRoute = /^\/edit\/[a-zA-Z0-9-]+$/.test(pathname) && 
                               pathname !== '/edit/draft';
    
    if (!isLibraryQuizRoute) {
      return { redirect: false, action: 'allow' };
    }

    if (auth.isLoading) {
      return { redirect: false, action: 'wait' };
    }

    if (!auth.isAuthenticated) {
      return { redirect: true, action: 'signin' };
    }

    return { redirect: false, action: 'allow' };
  };

  describe('Library quiz routes (/edit/:quizId)', () => {
    it('should require auth for library quiz routes', () => {
      const result = shouldRedirectToAuth('/edit/quiz-123', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(true);
      expect(result.action).toBe('signin');
    });

    it('should allow authenticated users to view library quizzes', () => {
      const result = shouldRedirectToAuth('/edit/quiz-123', {
        isLoading: false,
        isAuthenticated: true,
      });

      expect(result.redirect).toBe(false);
      expect(result.action).toBe('allow');
    });

    it('should wait while auth is loading', () => {
      const result = shouldRedirectToAuth('/edit/quiz-123', {
        isLoading: true,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(false);
      expect(result.action).toBe('wait');
    });

    it('should require auth for UUID-style quiz IDs', () => {
      const result = shouldRedirectToAuth('/edit/a1b2c3d4-e5f6-7890-abcd-ef1234567890', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(true);
      expect(result.action).toBe('signin');
    });
  });

  describe('Draft routes (/edit/draft)', () => {
    it('should NOT require auth for draft route', () => {
      const result = shouldRedirectToAuth('/edit/draft', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(false);
      expect(result.action).toBe('allow');
    });

    it('should allow unauthenticated users to view drafts', () => {
      const result = shouldRedirectToAuth('/edit/draft', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(false);
    });
  });

  describe('Non-edit routes', () => {
    it('should NOT require auth for landing page', () => {
      const result = shouldRedirectToAuth('/', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(false);
      expect(result.action).toBe('allow');
    });

    it('should NOT require auth for create route', () => {
      const result = shouldRedirectToAuth('/create', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(false);
      expect(result.action).toBe('allow');
    });

    it('should NOT require auth for play route', () => {
      const result = shouldRedirectToAuth('/play/123456', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(false);
      expect(result.action).toBe('allow');
    });

    it('should NOT require auth for host route', () => {
      const result = shouldRedirectToAuth('/host/123456', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(false);
      expect(result.action).toBe('allow');
    });
  });

  describe('Auth state transitions', () => {
    it('should redirect after auth finishes loading (unauthenticated)', () => {
      const auth = { isLoading: true, isAuthenticated: false };
      
      const beforeLoad = shouldRedirectToAuth('/edit/quiz-123', auth);
      expect(beforeLoad.action).toBe('wait');
      
      auth.isLoading = false;
      
      const afterLoad = shouldRedirectToAuth('/edit/quiz-123', auth);
      expect(afterLoad.redirect).toBe(true);
      expect(afterLoad.action).toBe('signin');
    });

    it('should allow access after auth finishes loading (authenticated)', () => {
      const auth = { isLoading: true, isAuthenticated: false };
      
      const beforeLoad = shouldRedirectToAuth('/edit/quiz-123', auth);
      expect(beforeLoad.action).toBe('wait');
      
      auth.isLoading = false;
      auth.isAuthenticated = true;
      
      const afterLoad = shouldRedirectToAuth('/edit/quiz-123', auth);
      expect(afterLoad.redirect).toBe(false);
      expect(afterLoad.action).toBe('allow');
    });
  });

  describe('Edge cases', () => {
    it('should handle /edit without trailing path', () => {
      const result = shouldRedirectToAuth('/edit', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(false);
    });

    it('should handle /edit/ with trailing slash', () => {
      const result = shouldRedirectToAuth('/edit/', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(false);
    });

    it('should handle special characters in URL (should not match)', () => {
      const result = shouldRedirectToAuth('/edit/quiz@123', {
        isLoading: false,
        isAuthenticated: false,
      });

      expect(result.redirect).toBe(false);
    });
  });
});
