/**
 * Online Exams Module - Zustand Store
 */

import { create } from 'zustand';
import api from './auth';

interface Question {
  id: number;
  question_type: string;
  question: string;
  options: string[] | null;
  marks: number;
  difficulty: string;
}

interface ExamGroup {
  id: number;
  uid: string;
  name: string;
  description?: string;
  exam_type: string;
  duration_minutes: number;
  total_marks: number;
  passing_marks: number;
  max_attempts: number;
  show_results: boolean;
  allow_review: boolean;
  is_random_order: boolean;
  question_count?: number;
  questions?: Question[];
  schedules?: any[];
  // Exam-review workflow (added 2026-07-21, see migration
  // 2026072100000010_exam_groups_status). Optional because legacy
  // groups may not have them populated.
  status?: 'draft' | 'pending_review' | 'approved' | 'rejected';
  rejection_reason?: string | null;
  reviewed_at?: string | null;
  reviewed_by?: number | null;
}

interface ExamAttempt {
  id: number;
  exam_group_id: number;
  started_at: string;
  submitted_at?: string;
  status: string;
  total_marks: number;
  obtained_marks: number;
  percentage: number;
  time_spent_seconds: number;
  allow_review: boolean;
  answers?: any[];
  questions?: Question[];
}

interface ExamAnswer {
  question_id: number;
  answer: string;
}

interface ExamStore {
  // State
  examGroups: ExamGroup[];
  currentExam: ExamGroup | null;
  currentAttempt: ExamAttempt | null;
  studentAttempts: ExamAttempt[];
  availableExams: any[];
  answers: Map<number, string>;
  timeRemaining: number;
  isSubmitting: boolean;
  error: string | null;
  
  // Actions
  fetchExamGroups: (filters?: any) => Promise<void>;
  fetchExamGroup: (id: number) => Promise<void>;
  createExamGroup: (data: Partial<ExamGroup>) => Promise<ExamGroup>;
  updateExamGroup: (id: number, data: Partial<ExamGroup>) => Promise<void>;
  deleteExamGroup: (id: number) => Promise<void>;
  
  // Questions
  fetchQuestions: (filters?: any) => Promise<Question[]>;
  createQuestion: (data: Partial<Question>) => Promise<Question>;
  bulkCreateQuestions: (questions: Partial<Question>[]) => Promise<void>;
  updateQuestion: (id: number, data: Partial<Question>) => Promise<void>;
  deleteQuestion: (id: number) => Promise<void>;
  
  // Exams (Student)
  fetchAvailableExams: () => Promise<void>;
  startExam: (examGroupId: number, scheduleId?: number) => Promise<void>;
  saveAnswer: (questionId: number, answer: string) => Promise<void>;
  submitExam: () => Promise<void>;
  fetchAttemptResults: (attemptId: number) => Promise<void>;
  
  // Results (Teacher)
  fetchExamResults: (filters?: any) => Promise<any[]>;
  fetchStudentAttempts: (examGroupId?: number) => Promise<void>;
  fetchExamStats: (examGroupId?: number) => Promise<any>;
  
  // Timer
  startTimer: () => void;
  stopTimer: () => void;
  resetExam: () => void;

  // ============ EXAM REVIEW WORKFLOW (admin / teacher) ============
  // Added 2026-07-21. See server migration
  // 2026072100000010_exam_groups_status and the new endpoints on
  // /api/exams/groups/pending, /groups/:id/submit, /groups/:id/reject,
  // /schedules/:id/publish.
  pendingGroups: ExamGroup[];
  fetchPendingGroups: () => Promise<void>;
  submitGroup:     (groupId: number) => Promise<ExamGroup>;
  createSchedule:  (data: any) => Promise<any>;
  publishSchedule: (scheduleId: number) => Promise<any>;
  rejectGroup:     (groupId: number, reason: string) => Promise<ExamGroup>;
  bulkRejectGroups: (groupIds: number[], reason: string) => Promise<{succeeded: number[]; failed: {id: number; reason: string}[]}>;
  fetchGroupAudit:  (groupId: number) => Promise<any[]>;
}

export const useExamStore = create<ExamStore>((set, get) => ({
  examGroups: [],
  currentExam: null,
  currentAttempt: null,
  studentAttempts: [],
  availableExams: [],
  answers: new Map(),
  timeRemaining: 0,
  isSubmitting: false,
  error: null,
  pendingGroups: [],
  
  // ============ EXAM GROUPS ============
  
  fetchExamGroups: async (filters) => {
    try {
      set({ error: null });
      const params = new URLSearchParams(filters || {});
      const response = await api.get(`/exams/groups?${params}`);
      set({ examGroups: response.data });
    } catch (error: any) {
      set({ error: error.message });
      console.error('Failed to fetch exam groups:', error);
    }
  },
  
  fetchExamGroup: async (id) => {
    try {
      set({ error: null });
      const response = await api.get(`/exams/groups/${id}`);
      set({ currentExam: response.data });
    } catch (error: any) {
      set({ error: error.message });
      console.error('Failed to fetch exam group:', error);
    }
  },
  
  createExamGroup: async (data) => {
    const response = await api.post('/exams/groups', data);
    set(state => ({ examGroups: [response.data, ...state.examGroups] }));
    return response.data;
  },
  
  updateExamGroup: async (id, data) => {
    const response = await api.put(`/exams/groups/${id}`, data);
    set(state => ({
      examGroups: state.examGroups.map(g => g.id === id ? { ...g, ...response.data } : g),
      currentExam: state.currentExam?.id === id ? { ...state.currentExam, ...response.data } : state.currentExam
    }));
  },
  
  deleteExamGroup: async (id) => {
    await api.delete(`/exams/groups/${id}`);
    set(state => ({
      examGroups: state.examGroups.filter(g => g.id !== id)
    }));
  },
  
  // ============ QUESTIONS ============
  
  fetchQuestions: async (filters) => {
    const params = new URLSearchParams(filters || {});
    const response = await api.get(`/exams/questions?${params}`);
    return response.data;
  },
  
  createQuestion: async (data) => {
    const response = await api.post('/exams/questions', data);
    return response.data;
  },
  
  bulkCreateQuestions: async (questions) => {
    await api.post('/exams/questions/bulk', { questions });
  },
  
  updateQuestion: async (id, data) => {
    await api.put(`/exams/questions/${id}`, data);
  },
  
  deleteQuestion: async (id) => {
    await api.delete(`/exams/questions/${id}`);
  },
  
  // ============ STUDENT EXAM ACTIONS ============
  
  fetchAvailableExams: async () => {
    try {
      const response = await api.get('/exams/available');
      set({ availableExams: response.data });
    } catch (error: any) {
      console.error('Failed to fetch available exams:', error);
    }
  },
  
  startExam: async (examGroupId, scheduleId) => {
    try {
      set({ error: null, isSubmitting: true });
      
      const response = await api.post('/exams/attempts/start', {
        exam_group_id: examGroupId,
        schedule_id: scheduleId
      });
      
      const attempt = response.data;
      
      // Initialize answers map
      const answersMap = new Map<number, string>();
      if (attempt.questions) {
        attempt.questions.forEach((q: Question) => {
          answersMap.set(q.id, '');
        });
      }
      
      set({
        currentAttempt: attempt,
        currentExam: { ...attempt, questions: attempt.questions },
        answers: answersMap,
        timeRemaining: (attempt.duration_minutes || 60) * 60,
        isSubmitting: false
      });
      
      // Start timer
      get().startTimer();
      
    } catch (error: any) {
      set({ error: error.response?.data?.error || 'Failed to start exam', isSubmitting: false });
      console.error('Failed to start exam:', error);
    }
  },
  
  saveAnswer: async (questionId, answer) => {
    const { currentAttempt, answers } = get();
    
    // Save to local state immediately
    const newAnswers = new Map(answers);
    newAnswers.set(questionId, answer);
    set({ answers: newAnswers });
    
    // Save to server (non-blocking)
    if (currentAttempt) {
      try {
        await api.post(`/exams/attempts/${currentAttempt.id}/answer`, {
          question_id: questionId,
          answer
        });
      } catch (error) {
        console.error('Failed to save answer:', error);
      }
    }
  },
  
  submitExam: async () => {
    const { currentAttempt, timeRemaining } = get();
    
    if (!currentAttempt) return;
    
    set({ isSubmitting: true });
    
    try {
      const response = await api.post(`/exams/attempts/${currentAttempt.id}/submit`);
      
      // Stop timer
      get().stopTimer();
      
      set({
        currentAttempt: response.data,
        isSubmitting: false
      });
      
      return response.data;
      
    } catch (error: any) {
      set({ error: error.message, isSubmitting: false });
      console.error('Failed to submit exam:', error);
      throw error;
    }
  },
  
  fetchAttemptResults: async (attemptId) => {
    const response = await api.get(`/exams/attempts/${attemptId}`);
    set({ currentAttempt: response.data });
    return response.data;
  },
  
  fetchStudentAttempts: async (examGroupId) => {
    const params = examGroupId ? `?exam_group_id=${examGroupId}` : '';
    const response = await api.get(`/exams/attempts${params}`);
    set({ studentAttempts: response.data });
  },
  
  // ============ TEACHER RESULTS ============
  
  fetchExamResults: async (filters) => {
    const params = new URLSearchParams(filters || {});
    const response = await api.get(`/exams/results?${params}`);
    return response.data;
  },
  
  fetchExamStats: async (examGroupId) => {
    const url = examGroupId ? `/exams/stats?exam_group_id=${examGroupId}` : '/exams/stats';
    const response = await api.get(url);
    return response.data;
  },
  
  // ============ TIMER ============
  
  startTimer: () => {
    const interval = setInterval(() => {
      const { timeRemaining } = get();
      
      if (timeRemaining <= 0) {
        clearInterval(interval);
        // Auto-submit
        get().submitExam();
        return;
      }
      
      set({ timeRemaining: timeRemaining - 1 });
    }, 1000);
    
    // Store interval ID for cleanup
    set({ timeRemaining: get().timeRemaining }); // Just trigger update
  },
  
  stopTimer: () => {
    // Timer will stop when component unmounts or exam is submitted
  },
  
  resetExam: () => {
    set({
      currentExam: null,
      currentAttempt: null,
      answers: new Map(),
      timeRemaining: 0,
      error: null
    });
  },

  // ============ EXAM REVIEW WORKFLOW ============

  // Admin: list groups awaiting review. Result also stored in
  // `pendingGroups` for the ExamReview queue UI.
  fetchPendingGroups: async () => {
    try {
      set({ error: null });
      const response = await api.get('/exams/groups/pending');
      set({ pendingGroups: response.data });
    } catch (error: any) {
      set({ error: error.message });
      console.error('Failed to fetch pending exam groups:', error);
    }
  },

  // Teacher: push a draft (or previously-rejected) group to the admin
  // review queue. Clears the stale rejection reason on the server.
  submitGroup: async (groupId) => {
    const response = await api.post(`/exams/groups/${groupId}/submit`);
    set(state => ({
      examGroups: state.examGroups.map(g =>
        g.id === groupId ? { ...g, ...response.data } : g
      ),
      pendingGroups: state.pendingGroups.map(g =>
        g.id === groupId ? { ...g, ...response.data } : g
      ),
    }));
    return response.data;
  },

  // Admin: create a draft schedule (inactive). Always followed by
  // publishSchedule() to make it visible to students.
  createSchedule: async (data) => {
    const response = await api.post('/exams/schedules', data);
    return response.data;
  },

  // Admin: publish a schedule. Server flips is_active=1 AND marks the
  // parent group as approved in the same call.
  publishSchedule: async (scheduleId) => {
    const response = await api.post(`/exams/schedules/${scheduleId}/publish`);
    return response.data;
  },

  // Admin: reject a pending group with a reason. The reason is stored
  // on the group and surfaces to the teacher on next view.
  rejectGroup: async (groupId, reason) => {
    const response = await api.post(`/exams/groups/${groupId}/reject`, { reason });
    set(state => ({
      // Remove from the pending queue (it's no longer pending)
      pendingGroups: state.pendingGroups.filter(g => g.id !== groupId),
      examGroups: state.examGroups.map(g =>
        g.id === groupId ? { ...g, ...response.data } : g
      ),
    }));
    return response.data;
  },

  // Admin: bulk-reject many groups at once with a single shared
  // reason. Server returns {succeeded, failed} — partial success
  // is normal. We drop the succeeded ones from the local pending
  // queue so the UI updates immediately.
  bulkRejectGroups: async (groupIds, reason) => {
    const response = await api.post('/exams/groups/bulk-reject', { groupIds, reason });
    set(state => ({
      pendingGroups: state.pendingGroups.filter(g => !response.data.succeeded.includes(g.id)),
    }));
    return response.data;
  },

  // Admin: fetch the audit log for a group (who submitted/rejected/
  // published and when). Newest first. Returns the raw array from
  // the server.
  fetchGroupAudit: async (groupId) => {
    const response = await api.get(`/exams/groups/${groupId}/audit`);
    return response.data;
  }
}));

// Format time helper
export const formatTime = (seconds: number): string => {
  const mins = Math.floor(seconds / 60);
  const secs = seconds % 60;
  return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
};

// Get question type icon
export const getQuestionTypeIcon = (type: string): string => {
  const icons: Record<string, string> = {
    'multiple-choice': '☑️',
    'true-false': '✓',
    'short-answer': '✏️',
    'essay': '📝',
    'fill-blank': '📋'
  };
  return icons[type] || '❓';
};

// Calculate grade
export const calculateGrade = (percentage: number): { grade: string; color: string } => {
  if (percentage >= 90) return { grade: 'A+', color: '#10b981' };
  if (percentage >= 80) return { grade: 'A', color: '#10b981' };
  if (percentage >= 70) return { grade: 'B+', color: '#3b82f6' };
  if (percentage >= 60) return { grade: 'B', color: '#3b82f6' };
  if (percentage >= 50) return { grade: 'C', color: '#f59e0b' };
  return { grade: 'F', color: '#ef4444' };
};

export default useExamStore;