/**
 * Enrollments Module - Zustand Store
 *
 * Talks to /api/enrollments:
 *   GET    /                     list (students see own only)
 *   GET    /pending              admin/teacher only (joins users + classes)
 *   POST   /                     student self-enrol -> pending; staff force-enrol -> approved
 *   POST   /:id/approve          admin/teacher only
 *   POST   /:id/reject           admin/teacher only (sets rejection_reason)
 *   POST   /:id/withdraw         student (own row only) or admin/teacher
 *   DELETE /:id                  admin-only soft delete
 *
 * Also reuses GET /classes to populate the class picker.
 */

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

export type EnrollmentRequestStatus = 'pending' | 'approved' | 'rejected' | 'withdrawn';
export type EnrollmentActiveStatus = 'active' | 'inactive';

export interface Enrollment {
  id: number;
  uid?: string;
  student_id: number;
  class_id: number;
  roll_number?: string | null;
  academic_year?: string;
  section?: string;
  status: EnrollmentActiveStatus;
  request_status?: EnrollmentRequestStatus | null;
  requested_at?: string | null;
  approved_by?: number | null;
  approved_at?: string | null;
  rejection_reason?: string | null;
  created_at?: string;
  updated_at?: string;
  // Joined by /pending endpoint:
  student_first_name?: string;
  student_last_name?: string;
  student_email?: string;
  class_name?: string;
  class_section?: string;
  // Echoed by POST / when an existing row was found:
  _idempotent?: boolean;
}

export interface ClassOption {
  id: number;
  name: string;
  section?: string;
  grade_level?: number;
  academic_year?: string;
}

interface EnrollmentStore {
  // State
  myEnrollments: Enrollment[];
  pendingApprovals: Enrollment[];
  classes: ClassOption[];          // class picker options
  isLoading: boolean;
  isSubmitting: boolean;
  error: string | null;

  // Student actions
  fetchMyEnrollments: () => Promise<void>;
  requestEnrollment: (classId: number) => Promise<Enrollment>;
  withdrawEnrollment: (id: number) => Promise<Enrollment>;

  // Staff actions
  fetchPending: () => Promise<void>;
  approveEnrollment: (id: number) => Promise<Enrollment>;
  bulkApproveEnrollments: (ids: number[]) => Promise<number>;
  bulkRejectEnrollments: (ids: number[], reason?: string) => Promise<number>;
  deleteEnrollment: (id: number) => Promise<void>;

  // Class picker
  fetchClasses: () => Promise<void>;

  // Local
  reset: () => void;
}

export const useEnrollmentStore = create<EnrollmentStore>((set, get) => ({
  myEnrollments: [],
  pendingApprovals: [],
  classes: [],
  isLoading: false,
  isSubmitting: false,
  error: null,

  // ============ STUDENT ============

  fetchMyEnrollments: async () => {
    try {
      set({ isLoading: true, error: null });
      const response = await api.get('/enrollments');
      set({ myEnrollments: response.data || [], isLoading: false });
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isLoading: false });
      console.error('Failed to fetch my enrollments:', error);
    }
  },

  requestEnrollment: async (classId) => {
    set({ isSubmitting: true, error: null });
    try {
      const response = await api.post('/enrollments', { class_id: classId });
      const created = response.data;
      set(state => ({
        myEnrollments: [
          created,
          ...state.myEnrollments.filter(e => e.id !== created.id),
        ],
        isSubmitting: false,
      }));
      return created;
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isSubmitting: false });
      throw error;
    }
  },

  withdrawEnrollment: async (id) => {
    set({ isSubmitting: true, error: null });
    try {
      const response = await api.post(`/enrollments/${id}/withdraw`);
      const updated = response.data;
      set(state => ({
        myEnrollments: state.myEnrollments.map(e => (e.id === id ? updated : e)),
        pendingApprovals: state.pendingApprovals.filter(e => e.id !== id),
        isSubmitting: false,
      }));
      return updated;
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isSubmitting: false });
      throw error;
    }
  },

  // ============ STAFF ============

  fetchPending: async () => {
    try {
      set({ isLoading: true, error: null });
      const response = await api.get('/enrollments/pending');
      set({ pendingApprovals: response.data || [], isLoading: false });
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isLoading: false });
      console.error('Failed to fetch pending enrollments:', error);
    }
  },

  approveEnrollment: async (id) => {
    set({ isSubmitting: true, error: null });
    try {
      const response = await api.post(`/enrollments/${id}/approve`);
      const updated = response.data;
      set(state => ({
        pendingApprovals: state.pendingApprovals.filter(e => e.id !== id),
        myEnrollments: state.myEnrollments.map(e => (e.id === id ? updated : e)),
        isSubmitting: false,
      }));
      return updated;
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isSubmitting: false });
      throw error;
    }
  },

  rejectEnrollment: async (id, reason) => {
    set({ isSubmitting: true, error: null });
    try {
      const response = await api.post(`/enrollments/${id}/reject`, {
        rejection_reason: reason || null,
      });
      const updated = response.data;
      set(state => ({
        pendingApprovals: state.pendingApprovals.filter(e => e.id !== id),
        myEnrollments: state.myEnrollments.map(e => (e.id === id ? updated : e)),
        isSubmitting: false,
      }));
      return updated;
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isSubmitting: false });
      throw error;
    }
  },

  bulkApproveEnrollments: async (ids) => {
    set({ isSubmitting: true, error: null });
    try {
      const response = await api.post('/enrollments/bulk-approve', { ids });
      const approvedIds = new Set(ids);
      set(state => ({
        pendingApprovals: state.pendingApprovals.filter(e => !approvedIds.has(e.id)),
        myEnrollments: state.myEnrollments.map(e => approvedIds.has(e.id) ? { ...e, request_status: 'approved', status: 'active' } : e),
        isSubmitting: false,
      }));
      return response.data?.count || ids.length;
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isSubmitting: false });
      throw error;
    }
  },

  bulkRejectEnrollments: async (ids, reason) => {
    set({ isSubmitting: true, error: null });
    try {
      const response = await api.post('/enrollments/bulk-reject', { ids, rejection_reason: reason });
      const rejectedIds = new Set(ids);
      set(state => ({
        pendingApprovals: state.pendingApprovals.filter(e => !rejectedIds.has(e.id)),
        myEnrollments: state.myEnrollments.map(e => rejectedIds.has(e.id) ? { ...e, request_status: 'rejected', status: 'inactive', rejection_reason: reason || null } : e),
        isSubmitting: false,
      }));
      return response.data?.count || ids.length;
    } catch (error: any) {
      set({ error: error.response?.data?.error || error.message, isSubmitting: false });
      throw error;
    }
  },

  deleteEnrollment: async (id) => {
    await api.delete(`/enrollments/${id}`);
    set(state => ({
      myEnrollments: state.myEnrollments.filter(e => e.id !== id),
      pendingApprovals: state.pendingApprovals.filter(e => e.id !== id),
    }));
  },

  // ============ CLASSES ============

  fetchClasses: async () => {
    try {
      const response = await api.get('/classes');
      const list = Array.isArray(response.data) ? response.data : [];
      set({ classes: list });
    } catch (error: any) {
      console.error('Failed to fetch classes:', error);
    }
  },

  reset: () => {
    set({
      myEnrollments: [],
      pendingApprovals: [],
      error: null,
    });
  },
}));

export default useEnrollmentStore;
