import { create } from 'zustand';
import { devtools, persist } from 'zustand/middleware';
import {
  Class,
  ClassWithRole,
  ClassWithRelations,
  Timetable,
  TimetableWithRelations,
  TimetableLesson,
  Lesson,
  LessonWithRelations,
  EnrollmentRequest,
  EnrollmentRequestWithProfile,
} from '../types/timetable.types';
import { timetableService } from '../services/timetableService';

// ============================================================================
// State Types
// ============================================================================

interface TimetableState {
  // Classes
  classes: Class[];
  currentClass: ClassWithRelations | null;
  myClasses: ClassWithRole[];
  myTeachingClasses: Class[];
  classesLoading: boolean;
  classesError: string | null;

  // Timetables
  timetables: Timetable[];
  currentTimetable: TimetableWithRelations | null;
  timetablesLoading: boolean;
  timetablesError: string | null;

  // Lessons
  lessons: Lesson[];
  currentLesson: LessonWithRelations | null;
  lessonsLoading: boolean;
  lessonsError: string | null;

  // Enrollment Requests
  enrollmentRequests: EnrollmentRequestWithProfile[];
  enrollmentRequestsLoading: boolean;
  enrollmentRequestsError: string | null;

  // Pagination
  totalCount: number;
  currentPage: number;
  pageSize: number;

  // Filters
  filterSubject: string | null;
  filterSchoolYear: string | null;
  filterAcademicTerm: string | null;
  searchQuery: string;
}

interface TimetableActions {
  // Class Actions
  fetchClasses: (params?: {
    subject?: string;
    schoolYear?: string;
    academicTerm?: string;
    search?: string;
    skip?: number;
    limit?: number;
  }) => Promise<void>;
  fetchClass: (classId: string) => Promise<void>;
  createClass: (data: {
    name: string;
    subject: string;
    schoolYear: string;
    academicTerm: string;
    description?: string;
  }) => Promise<Class>;
  updateClass: (classId: string, data: Partial<Class>) => Promise<void>;
  deleteClass: (classId: string) => Promise<void>;
  fetchMyClasses: () => Promise<void>;
  fetchMyTeachingClasses: () => Promise<void>;
  clearCurrentClass: () => void;

  // Class Teacher Actions
  addTeacherToClass: (classId: string, teacherId: string, isPrimary?: boolean) => Promise<void>;
  removeTeacherFromClass: (classId: string, teacherId: string) => Promise<void>;

  // Class Student Actions
  addStudentToClass: (classId: string, studentId: string) => Promise<void>;
  removeStudentFromClass: (classId: string, studentId: string) => Promise<void>;

  // Enrollment Request Actions
  fetchEnrollmentRequests: (classId: string) => Promise<void>;
  requestEnrollment: (classId: string, message?: string) => Promise<void>;
  respondToEnrollmentRequest: (requestId: string, status: 'approved' | 'rejected', responseMessage?: string) => Promise<void>;

  // Timetable Actions
  fetchTimetables: (params?: {
    classId?: string;
    type?: 'adhoc' | 'recurring';
    isActive?: boolean;
    skip?: number;
    limit?: number;
  }) => Promise<void>;
  fetchTimetable: (timetableId: string) => Promise<void>;
  createTimetable: (data: {
    classId: string;
    name: string;
    type: 'adhoc' | 'recurring';
    startDate: string;
    endDate: string;
    recurrenceRule?: string;
  }) => Promise<Timetable>;
  updateTimetable: (timetableId: string, data: Partial<Timetable>) => Promise<void>;
  deleteTimetable: (timetableId: string) => Promise<void>;
  fetchMyTimetables: () => Promise<void>;
  fetchMyTeachingTimetables: () => Promise<void>;
  clearCurrentTimetable: () => void;

  // Timetable Teacher Actions
  addTeacherToTimetable: (timetableId: string, teacherId: string, isPrimary?: boolean) => Promise<void>;
  removeTeacherFromTimetable: (timetableId: string, teacherId: string) => Promise<void>;

  // Timetable Lesson Actions
  addTimetableLesson: (timetableId: string, data: {
    dayOfWeek: number;
    startTime: string;
    endTime: string;
    room?: string;
    maxStudents?: number;
  }) => Promise<void>;
  updateTimetableLesson: (timetableId: string, lessonId: string, data: Partial<TimetableLesson>) => Promise<void>;
  removeTimetableLesson: (timetableId: string, lessonId: string) => Promise<void>;

  // Lesson Actions
  fetchLessons: (params?: {
    timetableId?: string;
    startDate?: string;
    endDate?: string;
    status?: 'scheduled' | 'completed' | 'cancelled';
    skip?: number;
    limit?: number;
  }) => Promise<void>;
  fetchLesson: (lessonId: string) => Promise<void>;
  generateLessons: (timetableId: string, startDate: string, endDate: string) => Promise<void>;
  cancelLesson: (lessonId: string, reason?: string) => Promise<void>;
  clearCurrentLesson: () => void;

  // Filter Actions
  setFilterSubject: (subject: string | null) => void;
  setFilterSchoolYear: (schoolYear: string | null) => void;
  setFilterAcademicTerm: (academicTerm: string | null) => void;
  setSearchQuery: (query: string) => void;
  setPage: (page: number) => void;
  setPageSize: (size: number) => void;
  clearFilters: () => void;
}

// ============================================================================
// Initial State
// ============================================================================

const initialState: TimetableState = {
  classes: [],
  currentClass: null,
  myClasses: [],
  myTeachingClasses: [],
  classesLoading: false,
  classesError: null,

  timetables: [],
  currentTimetable: null,
  timetablesLoading: false,
  timetablesError: null,

  lessons: [],
  currentLesson: null,
  lessonsLoading: false,
  lessonsError: null,

  enrollmentRequests: [],
  enrollmentRequestsLoading: false,
  enrollmentRequestsError: null,

  totalCount: 0,
  currentPage: 0,
  pageSize: 20,

  filterSubject: null,
  filterSchoolYear: null,
  filterAcademicTerm: null,
  searchQuery: '',
};

// ============================================================================
// Store
// ============================================================================

const useTimetableStore = create<TimetableState & TimetableActions>()(
  devtools(
    persist(
      (set, get) => ({
        ...initialState,

        // ============================================================================
        // Class Actions
        // ============================================================================

        fetchClasses: async (params = {}) => {
          set({ classesLoading: true, classesError: null });
          try {
            const response = await timetableService.getClasses(params);
            set({
              classes: response.items,
              totalCount: response.total,
              classesLoading: false,
            });
          } catch (error) {
            console.error('Failed to fetch classes:', error);
            set({
              classesError: error instanceof Error ? error.message : 'Failed to fetch classes',
              classesLoading: false,
            });
          }
        },

        fetchClass: async (classId: string) => {
          set({ classesLoading: true, classesError: null });
          try {
            const classData = await timetableService.getClass(classId);
            set({ currentClass: classData, classesLoading: false });
          } catch (error) {
            console.error('Failed to fetch class:', error);
            set({
              classesError: error instanceof Error ? error.message : 'Failed to fetch class',
              classesLoading: false,
            });
          }
        },

        createClass: async (data) => {
          const newClass = await timetableService.createClass(data);
          set((state) => ({
            classes: [newClass, ...state.classes],
          }));
          return newClass;
        },

        updateClass: async (classId, data) => {
          const updatedClass = await timetableService.updateClass(classId, data);
          set((state) => ({
            classes: state.classes.map((c) => (c.id === classId ? updatedClass : c)),
            currentClass: state.currentClass?.id === classId ? { ...state.currentClass, ...updatedClass } : state.currentClass,
          }));
        },

        deleteClass: async (classId) => {
          await timetableService.deleteClass(classId);
          set((state) => ({
            classes: state.classes.filter((c) => c.id !== classId),
            currentClass: state.currentClass?.id === classId ? null : state.currentClass,
          }));
        },

        fetchMyClasses: async () => {
          set({ classesLoading: true, classesError: null });
          try {
            const classes = await timetableService.getMyClasses();
            set({ myClasses: classes, classesLoading: false });
          } catch (error) {
            console.error('Failed to fetch my classes:', error);
            set({
              classesError: error instanceof Error ? error.message : 'Failed to fetch my classes',
              classesLoading: false,
            });
          }
        },

        fetchMyTeachingClasses: async () => {
          set({ classesLoading: true, classesError: null });
          try {
            const classes = await timetableService.getMyTeachingClasses();
            set({ myTeachingClasses: classes, classesLoading: false });
          } catch (error) {
            console.error('Failed to fetch my teaching classes:', error);
            set({
              classesError: error instanceof Error ? error.message : 'Failed to fetch my teaching classes',
              classesLoading: false,
            });
          }
        },

        clearCurrentClass: () => set({ currentClass: null }),

        addTeacherToClass: async (classId, teacherId, isPrimary = false) => {
          await timetableService.addTeacherToClass(classId, teacherId, isPrimary);
          await get().fetchClass(classId);
        },

        removeTeacherFromClass: async (classId, teacherId) => {
          await timetableService.removeTeacherFromClass(classId, teacherId);
          await get().fetchClass(classId);
        },

        addStudentToClass: async (classId, studentId) => {
          await timetableService.addStudentToClass(classId, studentId);
          await get().fetchClass(classId);
        },

        removeStudentFromClass: async (classId, studentId) => {
          await timetableService.removeStudentFromClass(classId, studentId);
          await get().fetchClass(classId);
        },

        // ============================================================================
        // Enrollment Request Actions
        // ============================================================================

        fetchEnrollmentRequests: async (classId) => {
          set({ enrollmentRequestsLoading: true, enrollmentRequestsError: null });
          try {
            const requests = await timetableService.getEnrollmentRequests(classId);
            set({ enrollmentRequests: requests, enrollmentRequestsLoading: false });
          } catch (error) {
            console.error('Failed to fetch enrollment requests:', error);
            set({
              enrollmentRequestsError: error instanceof Error ? error.message : 'Failed to fetch enrollment requests',
              enrollmentRequestsLoading: false,
            });
          }
        },

        requestEnrollment: async (classId, message) => {
          await timetableService.requestEnrollment(classId, message);
        },

        respondToEnrollmentRequest: async (requestId, status, responseMessage) => {
          await timetableService.respondToEnrollmentRequest(requestId, status, responseMessage);
          await get().fetchEnrollmentRequests(get().currentClass?.id || '');
        },

        // ============================================================================
        // Timetable Actions
        // ============================================================================

        fetchTimetables: async (params = {}) => {
          set({ timetablesLoading: true, timetablesError: null });
          try {
            const response = await timetableService.getTimetables(params);
            set({
              timetables: response.items,
              totalCount: response.total,
              timetablesLoading: false,
            });
          } catch (error) {
            console.error('Failed to fetch timetables:', error);
            set({
              timetablesError: error instanceof Error ? error.message : 'Failed to fetch timetables',
              timetablesLoading: false,
            });
          }
        },

        fetchTimetable: async (timetableId) => {
          set({ timetablesLoading: true, timetablesError: null });
          try {
            const timetable = await timetableService.getTimetable(timetableId);
            set({ currentTimetable: timetable, timetablesLoading: false });
          } catch (error) {
            console.error('Failed to fetch timetable:', error);
            set({
              timetablesError: error instanceof Error ? error.message : 'Failed to fetch timetable',
              timetablesLoading: false,
            });
          }
        },

        createTimetable: async (data) => {
          const newTimetable = await timetableService.createTimetable(data);
          set((state) => ({
            timetables: [newTimetable, ...state.timetables],
          }));
          return newTimetable;
        },

        updateTimetable: async (timetableId, data) => {
          const updatedTimetable = await timetableService.updateTimetable(timetableId, data);
          set((state) => ({
            timetables: state.timetables.map((t) => (t.id === timetableId ? updatedTimetable : t)),
            currentTimetable: state.currentTimetable?.id === timetableId ? { ...state.currentTimetable, ...updatedTimetable } : state.currentTimetable,
          }));
        },

        deleteTimetable: async (timetableId) => {
          await timetableService.deleteTimetable(timetableId);
          set((state) => ({
            timetables: state.timetables.filter((t) => t.id !== timetableId),
            currentTimetable: state.currentTimetable?.id === timetableId ? null : state.currentTimetable,
          }));
        },

        fetchMyTimetables: async () => {
          set({ timetablesLoading: true, timetablesError: null });
          try {
            const timetables = await timetableService.getMyTimetables();
            set({ timetables, timetablesLoading: false });
          } catch (error) {
            console.error('Failed to fetch my timetables:', error);
            set({
              timetablesError: error instanceof Error ? error.message : 'Failed to fetch my timetables',
              timetablesLoading: false,
            });
          }
        },

        fetchMyTeachingTimetables: async () => {
          set({ timetablesLoading: true, timetablesError: null });
          try {
            const timetables = await timetableService.getMyTeachingTimetables();
            set({ timetables, timetablesLoading: false });
          } catch (error) {
            console.error('Failed to fetch my teaching timetables:', error);
            set({
              timetablesError: error instanceof Error ? error.message : 'Failed to fetch my teaching timetables',
              timetablesLoading: false,
            });
          }
        },

        clearCurrentTimetable: () => set({ currentTimetable: null }),

        addTeacherToTimetable: async (timetableId, teacherId, isPrimary = false) => {
          await timetableService.addTeacherToTimetable(timetableId, teacherId, isPrimary);
          await get().fetchTimetable(timetableId);
        },

        removeTeacherFromTimetable: async (timetableId, teacherId) => {
          await timetableService.removeTeacherFromTimetable(timetableId, teacherId);
          await get().fetchTimetable(timetableId);
        },

        addTimetableLesson: async (timetableId, data) => {
          await timetableService.addTimetableLesson(timetableId, data);
          await get().fetchTimetable(timetableId);
        },

        updateTimetableLesson: async (timetableId, lessonId, data) => {
          await timetableService.updateTimetableLesson(timetableId, lessonId, data);
          await get().fetchTimetable(timetableId);
        },

        removeTimetableLesson: async (timetableId, lessonId) => {
          await timetableService.removeTimetableLesson(timetableId, lessonId);
          await get().fetchTimetable(timetableId);
        },

        // ============================================================================
        // Lesson Actions
        // ============================================================================

        fetchLessons: async (params = {}) => {
          set({ lessonsLoading: true, lessonsError: null });
          try {
            const response = await timetableService.getLessons(params);
            set({
              lessons: response.items,
              totalCount: response.total,
              lessonsLoading: false,
            });
          } catch (error) {
            console.error('Failed to fetch lessons:', error);
            set({
              lessonsError: error instanceof Error ? error.message : 'Failed to fetch lessons',
              lessonsLoading: false,
            });
          }
        },

        fetchLesson: async (lessonId) => {
          set({ lessonsLoading: true, lessonsError: null });
          try {
            const lesson = await timetableService.getLesson(lessonId);
            set({ currentLesson: lesson, lessonsLoading: false });
          } catch (error) {
            console.error('Failed to fetch lesson:', error);
            set({
              lessonsError: error instanceof Error ? error.message : 'Failed to fetch lesson',
              lessonsLoading: false,
            });
          }
        },

        generateLessons: async (timetableId, startDate, endDate) => {
          set({ lessonsLoading: true, lessonsError: null });
          try {
            await timetableService.generateLessons(timetableId, startDate, endDate);
            await get().fetchLessons({ timetableId });
            set({ lessonsLoading: false });
          } catch (error) {
            console.error('Failed to generate lessons:', error);
            set({
              lessonsError: error instanceof Error ? error.message : 'Failed to generate lessons',
              lessonsLoading: false,
            });
          }
        },

        cancelLesson: async (lessonId, reason) => {
          await timetableService.cancelLesson(lessonId, reason);
          await get().fetchLesson(lessonId);
        },

        clearCurrentLesson: () => set({ currentLesson: null }),

        // ============================================================================
        // Filter Actions
        // ============================================================================

        setFilterSubject: (subject) => set({ filterSubject: subject, currentPage: 0 }),
        setFilterSchoolYear: (schoolYear) => set({ filterSchoolYear: schoolYear, currentPage: 0 }),
        setFilterAcademicTerm: (academicTerm) => set({ filterAcademicTerm: academicTerm, currentPage: 0 }),
        setSearchQuery: (query) => set({ searchQuery: query, currentPage: 0 }),
        setPage: (page) => set({ currentPage: page }),
        setPageSize: (size) => set({ pageSize: size, currentPage: 0 }),

        clearFilters: () =>
          set({
            filterSubject: null,
            filterSchoolYear: null,
            filterAcademicTerm: null,
            searchQuery: '',
            currentPage: 0,
          }),
      }),
      {
        name: 'timetable-store',
        partialize: (state) => ({
          filterSubject: state.filterSubject,
          filterSchoolYear: state.filterSchoolYear,
          filterAcademicTerm: state.filterAcademicTerm,
          pageSize: state.pageSize,
        }),
      }
    ),
    { name: 'TimetableStore' }
  )
);

export default useTimetableStore;
