// ... existing imports import { User, ClassInfo, SystemConfig, Subject, School, Schedule, GameSession, StudentReward, LuckyDrawConfig, Attendance, LeaveRequest, AchievementConfig, SchoolCalendarEntry, TeacherExchangeConfig, Wish, Feedback, AIChatMessage, Todo } from '../types'; // ... existing getBaseUrl ... const getBaseUrl = () => { let isProd = false; try { // @ts-ignore if (typeof import.meta !== 'undefined' && import.meta.env && import.meta.env.PROD) { isProd = true; } } catch (e) {} if (isProd || (typeof window !== 'undefined' && window.location.port === '7860')) { return '/api'; } return 'http://localhost:7860/api'; }; const API_BASE_URL = getBaseUrl(); async function request(endpoint: string, options: RequestInit = {}) { const headers: any = { 'Content-Type': 'application/json', ...options.headers }; if (typeof window !== 'undefined') { const currentUser = JSON.parse(localStorage.getItem('user') || 'null'); const selectedSchoolId = localStorage.getItem('admin_view_school_id'); if (currentUser?.role === 'ADMIN' && selectedSchoolId) { headers['x-school-id'] = selectedSchoolId; } else if (currentUser?.schoolId) { headers['x-school-id'] = currentUser.schoolId; } if (currentUser?.role) { headers['x-user-role'] = currentUser.role; headers['x-user-username'] = currentUser.username; } } const res = await fetch(`${API_BASE_URL}${endpoint}`, { ...options, headers }); if (!res.ok) { if (res.status === 401) throw new Error('AUTH_FAILED'); const errorData = await res.json().catch(() => ({})); const errorMessage = errorData.error || errorData.message || `Server Error: ${res.status}`; if (errorData.error === 'PENDING_APPROVAL') throw new Error('PENDING_APPROVAL'); if (errorData.error === 'BANNED') throw new Error('BANNED'); if (errorData.error === 'CONFLICT') throw new Error(errorData.message); if (errorData.error === 'INVALID_PASSWORD') throw new Error('INVALID_PASSWORD'); throw new Error(errorMessage); } return res.json(); } export const api = { init: () => console.log('🔗 API:', API_BASE_URL), auth: { login: async (username: string, password: string): Promise => { const user = await request('/auth/login', { method: 'POST', body: JSON.stringify({ username, password }) }); if (typeof window !== 'undefined') { localStorage.setItem('user', JSON.stringify(user)); localStorage.removeItem('admin_view_school_id'); } return user; }, refreshSession: async (): Promise => { try { const user = await request('/auth/me'); if (typeof window !== 'undefined' && user) { localStorage.setItem('user', JSON.stringify(user)); } return user; } catch (e) { return null; } }, register: async (data: any): Promise => { return await request('/auth/register', { method: 'POST', body: JSON.stringify(data) }); }, updateProfile: async (data: any): Promise => { return await request('/auth/update-profile', { method: 'POST', body: JSON.stringify(data) }); }, logout: () => { if (typeof window !== 'undefined') { localStorage.removeItem('user'); localStorage.removeItem('admin_view_school_id'); } }, getCurrentUser: (): User | null => { if (typeof window !== 'undefined') { try { const stored = localStorage.getItem('user'); if (stored) return JSON.parse(stored); } catch (e) { localStorage.removeItem('user'); } } return null; } }, schools: { getPublic: () => request('/public/schools'), getAll: () => request('/schools'), add: (data: School) => request('/schools', { method: 'POST', body: JSON.stringify(data) }), update: (id: string, data: Partial) => request(`/schools/${id}`, { method: 'PUT', body: JSON.stringify(data) }), delete: (id: string) => request(`/schools/${id}`, { method: 'DELETE' }) }, users: { getAll: (options?: { global?: boolean; role?: string }) => { const params = new URLSearchParams(); if (options?.global) params.append('global', 'true'); if (options?.role) params.append('role', options.role); return request(`/users?${params.toString()}`); }, update: (id: string, data: Partial) => request(`/users/${id}`, { method: 'PUT', body: JSON.stringify(data) }), delete: (id: string) => request(`/users/${id}`, { method: 'DELETE' }), applyClass: (data: { userId: string, type: 'CLAIM'|'RESIGN', targetClass?: string, action: 'APPLY'|'APPROVE'|'REJECT' }) => request('/users/class-application', { method: 'POST', body: JSON.stringify(data) }), getTeachersForClass: (className: string) => request(`/classes/${encodeURIComponent(className)}/teachers`), saveMenuOrder: (userId: string, order: string[]) => request(`/users/${userId}/menu-order`, { method: 'PUT', body: JSON.stringify({ menuOrder: order }) }), // NEW }, students: { getAll: () => request('/students'), add: (data: any) => request('/students', { method: 'POST', body: JSON.stringify(data) }), update: (id: string, data: any) => request(`/students/${id}`, { method: 'PUT', body: JSON.stringify(data) }), delete: (id: string | number) => request(`/students/${id}`, { method: 'DELETE' }), promote: (data: { teacherFollows: boolean }) => request('/students/promote', { method: 'POST', body: JSON.stringify(data) }), transfer: (data: { studentId: string, targetClass: string }) => request('/students/transfer', { method: 'POST', body: JSON.stringify(data) }) }, classes: { getAll: () => request('/classes'), add: (data: ClassInfo) => request('/classes', { method: 'POST', body: JSON.stringify(data) }), delete: (id: string | number) => request(`/classes/${id}`, { method: 'DELETE' }) }, subjects: { getAll: () => request('/subjects'), add: (data: Subject) => request('/subjects', { method: 'POST', body: JSON.stringify(data) }), update: (id: string | number, data: Partial) => request(`/subjects/${id}`, { method: 'PUT', body: JSON.stringify(data) }), delete: (id: string | number) => request(`/subjects/${id}`, { method: 'DELETE' }) }, exams: { getAll: () => request('/exams'), save: (data: any) => request('/exams', { method: 'POST', body: JSON.stringify(data) }) }, courses: { getAll: () => request('/courses'), add: (data: any) => request('/courses', { method: 'POST', body: JSON.stringify(data) }), update: (id: string | number, data: any) => request(`/courses/${id}`, { method: 'PUT', body: JSON.stringify(data) }), delete: (id: string | number) => request(`/courses/${id}`, { method: 'DELETE' }) }, scores: { getAll: () => request('/scores'), add: (data: any) => request('/scores', { method: 'POST', body: JSON.stringify(data) }), update: (id: string | number, data: any) => request(`/scores/${id}`, { method: 'PUT', body: JSON.stringify(data) }), delete: (id: string | number) => request(`/scores/${id}`, { method: 'DELETE' }) }, schedules: { get: (params: { className?: string; teacherName?: string; grade?: string }) => { const qs = new URLSearchParams(params as any).toString(); return request(`/schedules?${qs}`); }, save: (data: Schedule) => request('/schedules', { method: 'POST', body: JSON.stringify(data) }), delete: (params: { className: string; dayOfWeek: number; period: number }) => { const qs = new URLSearchParams(params as any).toString(); return request(`/schedules?${qs}`, { method: 'DELETE' }); } }, attendance: { checkIn: (data: { studentId: string, date: string, status?: string }) => request('/attendance/check-in', { method: 'POST', body: JSON.stringify(data) }), get: (params: { className?: string, date?: string, studentId?: string }) => { const qs = new URLSearchParams(params as any).toString(); return request(`/attendance?${qs}`); }, batch: (data: { className: string, date: string, status?: string }) => request('/attendance/batch', { method: 'POST', body: JSON.stringify(data) }), update: (data: { studentId: string, date: string, status: string }) => request('/attendance/update', { method: 'PUT', body: JSON.stringify(data) }), applyLeave: (data: { studentId: string, studentName: string, className: string, reason: string, startDate: string, endDate: string }) => request('/leave', { method: 'POST', body: JSON.stringify(data) }), }, calendar: { get: (className: string) => request(`/attendance/calendar?className=${className}`), add: (data: SchoolCalendarEntry) => request('/attendance/calendar', { method: 'POST', body: JSON.stringify(data) }), delete: (id: string) => request(`/attendance/calendar/${id}`, { method: 'DELETE' }) }, stats: { getSummary: () => request('/stats') }, config: { get: () => request('/config'), getPublic: () => request('/public/config'), save: (data: SystemConfig) => request('/config', { method: 'POST', body: JSON.stringify(data) }) }, notifications: { getAll: (userId: string, role: string) => request(`/notifications?userId=${userId}&role=${role}`), }, games: { getMountainSession: (className: string) => request(`/games/mountain?className=${className}`), saveMountainSession: (data: GameSession) => request('/games/mountain', { method: 'POST', body: JSON.stringify(data) }), getLuckyConfig: (className?: string, ownerId?: string) => request(`/games/lucky-config?className=${className || ''}${ownerId ? `&ownerId=${ownerId}` : ''}`), saveLuckyConfig: (data: LuckyDrawConfig) => request('/games/lucky-config', { method: 'POST', body: JSON.stringify(data) }), drawLucky: (studentId: string) => request('/games/lucky-draw', { method: 'POST', body: JSON.stringify({ studentId }) }), grantReward: (data: { studentId: string, count: number, rewardType: string, name?: string }) => request('/games/grant-reward', { method: 'POST', body: JSON.stringify(data) }), getMonsterConfig: (className: string) => request(`/games/monster-config?className=${className}`), saveMonsterConfig: (data: any) => request('/games/monster-config', { method: 'POST', body: JSON.stringify(data) }), getZenConfig: (className: string) => request(`/games/zen-config?className=${className}`), saveZenConfig: (data: any) => request('/games/zen-config', { method: 'POST', body: JSON.stringify(data) }), }, achievements: { getConfig: (className: string) => request(`/achievements/config?className=${className}`), saveConfig: (data: AchievementConfig) => request('/achievements/config', { method: 'POST', body: JSON.stringify(data) }), getStudentAchievements: (studentId: string, semester?: string) => request(`/achievements/student?studentId=${studentId}${semester ? `&semester=${semester}` : ''}`), getClassHistory: (studentIds: string[]) => request(`/achievements/student?studentIds=${studentIds.join(',')}&semester=ALL`), // NEW grant: (data: { studentId: string, achievementId: string, semester: string }) => request('/achievements/grant', { method: 'POST', body: JSON.stringify(data) }), deleteRecord: (id: string) => request(`/achievements/record/${id}`, { method: 'DELETE' }), // NEW exchange: (data: { studentId: string, ruleId: string, teacherId?: string }) => request('/achievements/exchange', { method: 'POST', body: JSON.stringify(data) }), getMyRules: () => request('/achievements/teacher-rules'), saveMyRules: (data: TeacherExchangeConfig) => request('/achievements/teacher-rules', { method: 'POST', body: JSON.stringify(data) }), getRulesByTeachers: (teacherIds: string[]) => request(`/achievements/teacher-rules?teacherIds=${teacherIds.join(',')}`), }, rewards: { getMyRewards: (studentId: string, page = 1, limit = 20) => request(`/rewards?studentId=${studentId}&page=${page}&limit=${limit}&excludeType=CONSOLATION`), getClassRewards: (page = 1, limit = 20, className?: string) => { let qs = `scope=class&page=${page}&limit=${limit}&excludeType=CONSOLATION`; if (className) qs += `&className=${className}`; return request(`/rewards?${qs}`); }, addReward: (data: Partial) => request('/rewards', { method: 'POST', body: JSON.stringify(data) }), update: (id: string, data: Partial) => request(`/rewards/${id}`, { method: 'PUT', body: JSON.stringify(data) }), delete: (id: string) => request(`/rewards/${id}`, { method: 'DELETE' }), redeem: (id: string) => request(`/rewards/${id}/redeem`, { method: 'POST' }), }, batchDelete: (type: 'student' | 'score' | 'user', ids: string[]) => { return request('/batch-delete', { method: 'POST', body: JSON.stringify({ type, ids }) }); }, wishes: { getAll: (params: { teacherId?: string, studentId?: string, status?: string }) => { const qs = new URLSearchParams(params as any).toString(); return request(`/wishes?${qs}`); }, create: (data: Partial) => request('/wishes', { method: 'POST', body: JSON.stringify(data) }), fulfill: (id: string) => request(`/wishes/${id}/fulfill`, { method: 'POST' }), randomFulfill: (teacherId: string) => request('/wishes/random-fulfill', { method: 'POST', body: JSON.stringify({ teacherId }) }), }, feedback: { getAll: (params: { targetId?: string, creatorId?: string, type?: string, status?: string }) => { const qs = new URLSearchParams(params as any).toString(); return request(`/feedback?${qs}`); }, create: (data: Partial) => request('/feedback', { method: 'POST', body: JSON.stringify(data) }), update: (id: string, data: { status?: string, reply?: string }) => request(`/feedback/${id}`, { method: 'PUT', body: JSON.stringify(data) }), ignoreAll: (targetId: string) => request('/feedback/ignore-all', { method: 'POST', body: JSON.stringify({ targetId }) }), }, ai: { chat: (data: { text?: string, audio?: string, history?: { role: string, text?: string }[], enableThinking?: boolean, overrideSystemPrompt?: string, disableAudio?: boolean }) => request('/ai/chat', { method: 'POST', body: JSON.stringify(data) }), evaluate: (data: { question: string, audio?: string, image?: string }) => request('/ai/evaluate', { method: 'POST', body: JSON.stringify(data) }), resetPool: () => request('/ai/reset-pool', { method: 'POST' }), getStats: () => request('/ai/stats'), // NEW Detailed Stats }, todos: { // NEW getAll: () => request('/todos'), add: (content: string) => request('/todos', { method: 'POST', body: JSON.stringify({ content }) }), update: (id: string, data: Partial) => request(`/todos/${id}`, { method: 'PUT', body: JSON.stringify(data) }), delete: (id: string) => request(`/todos/${id}`, { method: 'DELETE' }), } };