/**
 * @fileoverview Reactive state management store
 * @version 2.0.0
 * @requirementsTraceability {@link Requirements.REQ_ARCH_002} - Application state management and reactive data flow
 * @requirementsTraceability {@link Requirements.REQ_DATA_001} - Quiz data management and persistence layer
 * @requirementsTraceability {@link Requirements.REQ_DATA_002} - Local storage for user preferences and settings
 */

import { AuthService } from '../services/AuthService';
import { QuizService } from '../services/QuizService';
import { SettingsManager } from '../services/SettingsManager';
import { AppState, FilterType, Quiz, QuizProgress, User, ViewMode } from '../types/index';

export class AppStore {
  private static instance: AppStore;
  private state: AppState;
  private listeners: Set<(state: AppState) => void> = new Set();
  private quizService: QuizService;
  private authService: AuthService;
  private unsubscribeAuth: (() => void) | null = null;

  private constructor() {
    this.quizService = QuizService.getInstance();
    this.authService = AuthService.getInstance();
    this.state = this.getInitialState();
    this.loadCompletedQuizzes();
    this.setupAuthSubscription();
  }

  static getInstance(): AppStore {
    if (!AppStore.instance) {
      AppStore.instance = new AppStore();
    }
    return AppStore.instance;
  }

  private getInitialState(): AppState {
    // Load saved view mode preference
    const savedViewMode = localStorage.getItem('quiz-view-mode') as ViewMode;
    const viewMode =
      savedViewMode === 'single' || savedViewMode === 'list' ? savedViewMode : 'list';

    // Initialize settings manager and get default settings
    const settingsManager = SettingsManager.getInstance();
    const settings = settingsManager.getSettings();

    // Get initial auth state
    const authState = this.authService.getAuthState();

    return {
      quizzes: [],
      currentQuiz: null,
      filteredQuizzes: [],
      userAnswers: {},
      currentFilter: 'all',
      searchTerm: '',
      theme: { mode: 'system', color: 'blue' },
      settings,
      auth: {
        isAuthenticated: authState.isAuthenticated,
        user: authState.user,
        token: authState.token,
        isLoading: authState.isLoading,
        error: authState.error,
        showLoginModal: false,
      },
      ui: {
        loading: false,
        showWelcome: true,
        showResults: false,
        showCelebration: false,
        viewMode,
        submitBarVisible: false,
      },
      quiz: {
        completedQuizzes: new Set(),
        quizProgress: {},
        isCompleted: false,
        currentQuestionIndex: 0,
      },
      lastResult: null,
    };
  }

  getState(): AppState {
    return { ...this.state };
  }

  subscribe(callback: (state: AppState) => void): () => void {
    this.listeners.add(callback);
    return () => {
      this.listeners.delete(callback);
    };
  }

  private setState(updates: Partial<AppState>): void {
    this.state = { ...this.state, ...updates };
    this.notifyListeners();
  }

  private notifyListeners(): void {
    this.listeners.forEach(callback => callback(this.getState()));
  }

  // Actions
  async loadQuizzes(): Promise<void> {
    this.setState({ ui: { ...this.state.ui, loading: true } });

    try {
      const quizzes = await this.quizService.getAllQuizzes();
      this.setState({
        quizzes,
        filteredQuizzes: quizzes,
        ui: {
          ...this.state.ui,
          loading: false,
          showWelcome: quizzes.length === 0,
        },
      });
    } catch (error) {
      this.setState({ ui: { ...this.state.ui, loading: false } });
      throw error;
    }
  }

  selectQuiz(quiz: Quiz): void;
  selectQuiz(quizId: string): void;
  selectQuiz(quizOrId: Quiz | string): void {
    let quiz: Quiz;

    if (typeof quizOrId === 'string') {
      const foundQuiz = this.state.quizzes.find(q => q.id === quizOrId);
      if (!foundQuiz) {
        throw new Error(`Quiz with ID ${quizOrId} not found`);
      }
      quiz = foundQuiz;
    } else {
      quiz = quizOrId;
    }

    this.setState({
      currentQuiz: quiz,
      userAnswers: {},
      ui: { ...this.state.ui, showWelcome: false },
    });
  }

  updateAnswer(questionId: string, answer: string): void {
    this.setState({
      userAnswers: {
        ...this.state.userAnswers,
        [questionId]: answer,
      },
    });
  }

  setFilter(filter: FilterType): void {
    this.setState({ currentFilter: filter });
    this.applyFilters();
  }

  setSearchTerm(term: string): void {
    this.setState({ searchTerm: term });
    this.applyFilters();
  }

  setViewMode(mode: ViewMode): void {
    this.setState({
      ui: { ...this.state.ui, viewMode: mode },
    });
    // Save preference to localStorage
    localStorage.setItem('quiz-view-mode', mode);
  }

  private applyFilters(): void {
    let filtered = [...this.state.quizzes];

    // Apply search filter
    if (this.state.searchTerm) {
      const term = this.state.searchTerm.toLowerCase();
      filtered = filtered.filter(
        quiz =>
          quiz.title.toLowerCase().includes(term) ||
          (quiz.description && quiz.description.toLowerCase().includes(term)) ||
          (quiz.category && quiz.category.toLowerCase().includes(term))
      );
    }

    // Apply category filter
    switch (this.state.currentFilter) {
      case 'recent':
        filtered.sort(
          (a, b) =>
            new Date(b.updatedAt || b.createdAt || '').getTime() -
            new Date(a.updatedAt || a.createdAt || '').getTime()
        );
        break;
      case 'favorites':
        filtered = filtered.filter(quiz => localStorage.getItem(`favorite-${quiz.id}`) === 'true');
        break;
    }

    this.setState({ filteredQuizzes: filtered });
  }

  showResults(): void {
    this.setState({
      ui: { ...this.state.ui, showResults: true },
    });
  }

  hideResults(): void {
    this.setState({
      ui: { ...this.state.ui, showResults: false },
    });
  }

  retakeQuiz(): void {
    this.setState({
      userAnswers: {},
      ui: { ...this.state.ui, showResults: false },
    });
  }

  // Favorites functionality
  isFavorite(quizId: string): boolean {
    return localStorage.getItem(`favorite-${quizId}`) === 'true';
  }

  toggleFavorite(quizId: string): void {
    const currentValue = this.isFavorite(quizId);
    localStorage.setItem(`favorite-${quizId}`, (!currentValue).toString());

    // Refresh filtered quizzes if we're on favorites view
    if (this.state.currentFilter === 'favorites') {
      this.applyFilters();
    }
  }

  async submitQuiz(): Promise<any> {
    if (!this.state.currentQuiz) {
      throw new Error('No quiz selected');
    }

    const totalQuestions = this.state.currentQuiz.questions.length;
    const answeredQuestions = Object.keys(this.state.userAnswers).length;

    // Allow partial submissions but warn the user
    if (answeredQuestions < totalQuestions) {
      console.warn(
        `⚠️ Submitting incomplete quiz: ${answeredQuestions}/${totalQuestions} answered`
      );

      // For development/testing, allow partial submissions
      // In production, you might want to show a confirmation dialog instead
      if (process.env.NODE_ENV === 'production' && answeredQuestions === 0) {
        throw new Error('Please answer at least one question before submitting');
      }
    }

    try {
      const result = await this.quizService.submitQuiz(
        this.state.currentQuiz.id,
        this.state.userAnswers
      );

      // Store the result in state for the ResultsModal to access
      this.state.lastResult = result;

      // Mark quiz as completed
      this.markQuizCompleted(this.state.currentQuiz.id, result);

      this.showResults();
      return result;
    } catch (error) {
      throw error;
    }
  }

  /**
   * Load completed quizzes from localStorage
   */
  private loadCompletedQuizzes(): void {
    try {
      const stored = localStorage.getItem('completed-quizzes');
      if (stored) {
        const completedIds = JSON.parse(stored);
        this.state.quiz.completedQuizzes = new Set(completedIds);
      }

      const progressStored = localStorage.getItem('quiz-progress');
      if (progressStored) {
        this.state.quiz.quizProgress = JSON.parse(progressStored);
      }
    } catch (error) {
      console.warn('Failed to load completed quiz data:', error);
    }
  }

  /**
   * Save completed quizzes to localStorage
   */
  private saveCompletedQuizzes(): void {
    try {
      const completedIds = Array.from(this.state.quiz.completedQuizzes);
      localStorage.setItem('completed-quizzes', JSON.stringify(completedIds));
      localStorage.setItem('quiz-progress', JSON.stringify(this.state.quiz.quizProgress));
    } catch (error) {
      console.error('Failed to save completed quiz data:', error);
    }
  }

  /**
   * Mark a quiz as completed
   */
  markQuizCompleted(quizId: string, result: any): void {
    this.state.quiz.completedQuizzes.add(quizId);

    const progress: QuizProgress = {
      quizId,
      status: 'completed',
      answers: this.state.userAnswers,
      completedAt: new Date(),
      score: result.score,
      timeSpent: result.timeSpent,
    };

    this.state.quiz.quizProgress[quizId] = progress;
    this.state.quiz.isCompleted = true;

    this.saveCompletedQuizzes();
    this.notifyListeners();

    console.log(`✅ Quiz completed: ${quizId}`, progress);
  }

  /**
   * Check if a quiz is completed
   */
  isQuizCompleted(quizId: string): boolean {
    return this.state.quiz.completedQuizzes.has(quizId);
  }

  /**
   * Get quiz progress for a specific quiz
   */
  getQuizProgress(quizId: string): QuizProgress | undefined {
    return this.state.quiz.quizProgress[quizId];
  }

  /**
   * Get all completed quiz IDs
   */
  getCompletedQuizIds(): string[] {
    return Array.from(this.state.quiz.completedQuizzes);
  }

  /**
   * Reset quiz completion state
   */
  resetQuizCompletion(): void {
    this.state.quiz.isCompleted = false;
    this.state.quiz.currentQuestionIndex = 0;
    this.notifyListeners();
  }

  /**
   * Start a new quiz (reset completion state)
   */
  startQuiz(quiz: Quiz): void {
    // Validate quiz has questions
    if (!quiz.questions || !Array.isArray(quiz.questions) || quiz.questions.length === 0) {
      console.error('Cannot start quiz: missing or invalid questions', quiz);
      throw new Error('Quiz has no questions available');
    }

    this.selectQuiz(quiz);
    this.resetQuizCompletion();

    // Create or update progress entry
    const progress: QuizProgress = {
      quizId: quiz.id,
      status: 'in-progress',
      answers: {},
      startedAt: new Date(),
    };

    this.state.quiz.quizProgress[quiz.id] = progress;
    this.saveCompletedQuizzes();

    // Auto-hide sidebar on mobile for better UX
    try {
      // Import SidebarToggle dynamically to avoid circular dependencies
      import('../components/SidebarToggle').then(({ SidebarToggle }) => {
        const sidebarToggle = SidebarToggle.getInstance();
        if (sidebarToggle) {
          sidebarToggle.autoHideOnMobileForQuiz();
        }
      });
    } catch (error) {
      console.warn('Could not auto-hide sidebar on mobile:', error);
    }

    console.log(`🚀 Started quiz: ${quiz.id}`);
  }

  /**
   * Show celebration (called before results)
   */
  showCelebration(): void {
    this.state.ui.showCelebration = true;
    this.notifyListeners();

    // Auto-hide celebration after delay
    setTimeout(() => {
      this.state.ui.showCelebration = false;
      this.notifyListeners();
    }, 3000);
  }

  /**
   * Update submit bar visibility
   */
  updateSubmitBarVisibility(): void {
    const shouldShow =
      this.state.currentQuiz &&
      !this.state.ui.showWelcome &&
      !this.state.ui.showResults &&
      !this.state.quiz.isCompleted;

    this.state.ui.submitBarVisible = shouldShow || false;
    this.notifyListeners();
  }

  /**
   * Update current question index
   */
  setCurrentQuestionIndex(index: number): void {
    this.state.quiz.currentQuestionIndex = index;

    // Update progress
    if (this.state.currentQuiz) {
      const progress = this.state.quiz.quizProgress[this.state.currentQuiz.id];
      if (progress) {
        progress.currentQuestion = index;
        progress.answers = { ...this.state.userAnswers };
        this.saveCompletedQuizzes();
      }
    }

    this.notifyListeners();
  }

  /**
   * Setup authentication service subscription
   *
   * @description Subscribes to auth service state changes and updates app state
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   * @requirements REQ-AUTH-013 (Auth state synchronization)
   */
  private setupAuthSubscription(): void {
    this.unsubscribeAuth = this.authService.subscribe(authState => {
      this.setState({
        auth: {
          ...this.state.auth,
          isAuthenticated: authState.isAuthenticated,
          user: authState.user,
          token: authState.token,
          isLoading: authState.isLoading,
          error: authState.error,
        },
      });
    });
  }

  /**
   * Show login modal
   *
   * @description Displays the login modal by updating state
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  showLoginModal(): void {
    this.setState({
      auth: { ...this.state.auth, showLoginModal: true },
    });
  }

  /**
   * Hide login modal
   *
   * @description Hides the login modal by updating state
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  hideLoginModal(): void {
    this.setState({
      auth: { ...this.state.auth, showLoginModal: false },
    });
  }

  /**
   * Authenticate user
   *
   * @description Triggers user authentication through auth service
   *
   * @param {object} credentials - User login credentials
   * @returns {Promise<boolean>} Success status
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  async login(credentials: { username: string; password: string }): Promise<boolean> {
    return this.authService.login(credentials);
  }

  /**
   * Log out current user
   *
   * @description Logs out user through auth service
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  async logout(): Promise<void> {
    await this.authService.logout();
  }

  /**
   * Get current user
   *
   * @description Returns current authenticated user
   *
   * @returns {User | null} Current user or null
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  getCurrentUser(): User | null {
    return this.state.auth.user;
  }

  /**
   * Check if user is authenticated
   *
   * @description Returns authentication status
   *
   * @returns {boolean} Whether user is authenticated
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  isAuthenticated(): boolean {
    return this.state.auth.isAuthenticated;
  }

  /**
   * Make authenticated API request
   *
   * @description Helper for making authenticated API requests
   *
   * @param {string} url - API endpoint
   * @param {RequestInit} options - Fetch options
   * @returns {Promise<Response>} API response
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  async authenticatedFetch(url: string, options: RequestInit = {}): Promise<Response> {
    return this.authService.authenticatedFetch(url, options);
  }

  /**
   * Clean up subscriptions
   *
   * @description Cleans up auth service subscription
   *
   * @since 2025-08-04
   * @author Claude Code Agent
   */
  destroy(): void {
    this.unsubscribeAuth?.();
  }
}
