import { Attachment, AttachmentType, Comment, Course, Lesson, LessonMedia } from '../types'; import { apiRequest } from './api'; export const initDB = async (): Promise => undefined; type ApiAsset = { id: string; name: string; kind: 'document' | 'spreadsheet' | 'archive' | 'image' | 'link'; url: string; description: string; }; type ApiCourse = { id: string; title: string; description: string; category: string; coverImageUrl: string | null; status: 'draft' | 'published' | 'archived'; progress?: number; lastActivity?: string | null; instructor: { name: string }; lessons: Array<{ id: string; title: string; description: string; durationSeconds: number | null; accessLevel: 'public' | 'enrolled'; media: Array<{ id: string; provider: string; externalId: string; playbackUrl: string | null; embedUrl: string | null; status: 'processing' | 'ready' | 'failed'; durationSeconds: number | null; }>; assets: ApiAsset[]; }>; assets: ApiAsset[]; }; const toAttachmentType = (kind: ApiAsset['kind']): AttachmentType => { if (kind === 'document') return 'doc'; if (kind === 'archive') return 'zip'; return kind; }; const toAttachment = (asset: ApiAsset): Attachment => ({ id: asset.id, name: asset.name, type: toAttachmentType(asset.kind), url: asset.url, description: asset.description, }); const toDuration = (seconds: number | null) => { if (!seconds) return '—'; const minutes = Math.round(seconds / 60); return minutes >= 60 ? `${Math.floor(minutes / 60)}h ${minutes % 60}m` : `${minutes}m`; }; const toCourse = (course: ApiCourse): Course => ({ id: course.id, title: course.title, description: course.description, category: course.category, thumbnail: course.coverImageUrl || 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?auto=format&fit=crop&w=800&q=80', instructor: course.instructor.name, status: course.status === 'draft' ? 'draft' : 'published', progress: course.progress, lastActivity: course.lastActivity || undefined, duration: `${course.lessons.length} Aulas`, lessons: course.lessons.map((lesson): Lesson => { const media: LessonMedia[] = lesson.media.map((item) => ({ id: item.id, provider: item.provider, externalId: item.externalId, playbackUrl: item.playbackUrl, embedUrl: item.embedUrl, status: item.status, durationSeconds: item.durationSeconds, })); return { id: lesson.id, title: lesson.title, description: lesson.description, duration: toDuration(lesson.durationSeconds), isFree: lesson.accessLevel === 'public', videoUrl: media[0]?.playbackUrl || media[0]?.embedUrl || '', mediaProvider: media[0]?.provider, media, attachments: lesson.assets.map(toAttachment), }; }), attachments: course.assets.map(toAttachment), }); const toSeconds = (duration: string) => { const hours = Number(duration.match(/(\d+)h/)?.[1] || 0); const minutes = Number(duration.match(/(\d+)m/)?.[1] || 0); const seconds = hours * 3600 + minutes * 60; return seconds || null; }; const toAssetKind = (type: AttachmentType): ApiAsset['kind'] => { if (type === 'doc' || type === 'pdf') return 'document'; if (type === 'zip') return 'archive'; if (type === 'video') return 'link'; return type; }; const toAssetPayload = (attachment: Attachment) => ({ name: attachment.name, kind: toAssetKind(attachment.type), url: attachment.url, description: attachment.description || '', accessLevel: 'enrolled' as const, }); const toCoursePayload = (course: Course) => ({ title: course.title, description: course.description, category: course.category, coverImageUrl: course.thumbnail && !course.thumbnail.startsWith('blob:') ? course.thumbnail : null, status: course.status || 'published', assets: (course.attachments || []).filter((attachment) => attachment.url && attachment.url !== '#').map(toAssetPayload), lessons: course.lessons.map((lesson) => ({ id: /^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(lesson.id) ? lesson.id : undefined, title: lesson.title, description: lesson.description || '', durationSeconds: toSeconds(lesson.duration), accessLevel: lesson.isFree ? 'public' as const : 'enrolled' as const, media: lesson.media?.length ? lesson.media.map((media) => ({ provider: media.provider, externalId: media.externalId, playbackUrl: media.playbackUrl || null, embedUrl: media.embedUrl || null, status: media.status, durationSeconds: media.durationSeconds || null, })) : lesson.videoUrl && !lesson.videoUrl.startsWith('blob:') ? [{ provider: lesson.mediaProvider || 'external', externalId: lesson.videoUrl, playbackUrl: lesson.videoUrl, status: 'ready' as const }] : [], assets: (lesson.attachments || []).filter((attachment) => attachment.url && attachment.url !== '#').map(toAssetPayload), })), }); export const getCourses = async (): Promise => { const response = await apiRequest<{ data: ApiCourse[] }>('/courses'); return response.data.map(toCourse); }; export const getManagedCourses = async (): Promise => { const response = await apiRequest<{ data: ApiCourse[] }>('/manage/courses'); return response.data.map(toCourse); }; export const getMyLearningCourses = async (): Promise => { const response = await apiRequest<{ data: ApiCourse[] }>('/courses/me/learning'); return response.data.map(toCourse); }; export const getCourseById = async (id: string): Promise => { try { const response = await apiRequest<{ data: ApiCourse }>(`/courses/${id}`); return toCourse(response.data); } catch { return null; } }; export const saveCourse = async (course: Course): Promise => { const payload = toCoursePayload(course); const isExisting = /^[0-9a-f]{8}-[0-9a-f-]{27}$/i.test(course.id); if (isExisting) { await apiRequest(`/manage/courses/${course.id}`, { method: 'PATCH', body: JSON.stringify(payload) }); } else { await apiRequest('/manage/courses', { method: 'POST', body: JSON.stringify(payload) }); } }; export const deleteCourse = async (id: string): Promise => { await apiRequest(`/manage/courses/${id}`, { method: 'DELETE' }); }; type ApiComment = { id: string; courseId: string; lessonId: string | null; user: string; text: string; createdAt: string; reply?: string | null; replyCreatedAt?: string | null; }; const toComment = (comment: ApiComment): Comment => ({ id: comment.id, courseId: comment.courseId, lessonId: comment.lessonId || undefined, user: comment.user, text: comment.text, date: new Intl.DateTimeFormat('pt-BR').format(new Date(comment.createdAt)), reply: comment.reply || undefined, replyDate: comment.replyCreatedAt ? new Intl.DateTimeFormat('pt-BR').format(new Date(comment.replyCreatedAt)) : undefined, }); export const getComments = async (courseId: string): Promise => { const response = await apiRequest<{ data: ApiComment[] }>(`/courses/${courseId}/comments`); return response.data.map(toComment); }; export const saveComment = async (comment: Pick): Promise => { const response = await apiRequest<{ data: ApiComment }>(`/courses/${comment.courseId}/comments`, { method: 'POST', body: JSON.stringify({ lessonId: comment.lessonId || null, text: comment.text }), }); return toComment(response.data); }; export const replyToComment = async (commentId: string, text: string): Promise => { await apiRequest(`/comments/${commentId}/reply`, { method: 'PUT', body: JSON.stringify({ text }) }); }; export const moderateComment = async (commentId: string): Promise => { await apiRequest(`/comments/${commentId}`, { method: 'DELETE' }); }; export const getCompletedLessonIds = async (courseId: string): Promise => { const progress = await getLessonProgress(courseId); return progress.filter((item) => item.completedAt).map((item) => item.lessonId); }; export type LessonProgress = { lessonId: string; watchedSeconds: number; completedAt: string | null }; export const getLessonProgress = async (courseId: string): Promise => { const response = await apiRequest<{ data: LessonProgress[] }>(`/courses/${courseId}/progress`); return response.data; }; export const saveLessonCompletion = async (lessonId: string, completed: boolean, watchedSeconds?: number): Promise => { await apiRequest(`/lessons/${lessonId}/progress`, { method: 'PUT', body: JSON.stringify({ completed, watchedSeconds }), }); }; export const saveLessonProgress = async (lessonId: string, watchedSeconds: number): Promise => { await apiRequest(`/lessons/${lessonId}/progress`, { method: 'PUT', body: JSON.stringify({ watchedSeconds }) }); }; export const incrementViews = async (_courseId: string): Promise => undefined;