'use strict'; const PERSIAN_WEEKDAYS = ['یکشنبه', 'دوشنبه', 'سه‌شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه']; const IRAN_WEEK_ORDER = [6, 0, 1, 2, 3, 4, 5]; const toDate = (value) => { if (!value) return null; const date = value instanceof Date ? value : new Date(value); return Number.isNaN(date.getTime()) ? null : date; }; const formatClockPart = (time) => { const raw = String(time || '').trim(); if (!raw) return ''; const [hoursRaw, minutesRaw] = raw.split(':'); const hours = String(parseInt(hoursRaw, 10)); if (hours === 'NaN') return ''; if (!minutesRaw || minutesRaw === '00') return hours; return `${hours}:${minutesRaw}`; }; const formatCourseTime = (startTime, endTime) => { const start = formatClockPart(startTime); const end = formatClockPart(endTime); if (!start) return ''; if (!end) return start; return `از ساعت ${start} تا ${end}`; }; const weekdayIndex = (value) => { const date = toDate(value); return date ? date.getDay() : null; }; const joinFaList = (items) => { if (!items.length) return ''; if (items.length === 1) return items[0]; if (items.length === 2) return `${items[0]} و ${items[1]}`; return `${items.slice(0, -1).join('، ')} و ${items[items.length - 1]}`; }; const normalizeWeekdays = (days) => { if (!Array.isArray(days)) return []; const unique = []; const seen = new Set(); for (const value of days) { const index = Number(value); if (!Number.isInteger(index) || index < 0 || index > 6 || seen.has(index)) continue; seen.add(index); unique.push(index); } unique.sort((a, b) => IRAN_WEEK_ORDER.indexOf(a) - IRAN_WEEK_ORDER.indexOf(b)); return unique; }; const normalizeClockTime = (value) => { if (value == null) return ''; const raw = String(value).trim(); if (!raw) return ''; const match = raw.match(/^(\d{1,2})(?::(\d{1,2}))?$/); if (!match) return ''; const hours = Number(match[1]); const minutes = Number(match[2] || 0); if (hours > 23 || minutes > 59) return ''; return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`; }; const formatClassDaysFromIndexes = (days = []) => { const indexes = normalizeWeekdays(days); return joinFaList(indexes.map((index) => PERSIAN_WEEKDAYS[index]).filter(Boolean)); }; const formatClassDays = (sessions = []) => { const indexes = []; const seen = new Set(); for (const session of sessions) { const dayIndex = weekdayIndex(session?.day); if (dayIndex == null || seen.has(dayIndex)) continue; seen.add(dayIndex); indexes.push(dayIndex); } return formatClassDaysFromIndexes(indexes); }; const formatClassStartDate = (value) => { const date = toDate(value); if (!date) return ''; try { return date.toLocaleDateString('fa-IR'); } catch { return date.toISOString().slice(0, 10); } }; const buildClassScheduleContext = (classDoc, sessions = [], currentSession = null) => { const sortedSessions = [...sessions].sort((a, b) => { const left = toDate(a?.day)?.getTime() || 0; const right = toDate(b?.day)?.getTime() || 0; return left - right; }); const sessionForTime = currentSession || sortedSessions[0] || null; const storedDays = formatClassDaysFromIndexes(classDoc?.days); const storedTime = formatCourseTime(classDoc?.startTime, classDoc?.endTime); return { classStartDate: formatClassStartDate(classDoc?.startDate || sortedSessions[0]?.day), classDays: storedDays || formatClassDays(sortedSessions), courseTime: storedTime || formatCourseTime(sessionForTime?.startTime, sessionForTime?.endTime) }; }; const calculateClassEndDate = (startDate, days = [], numberOfSessions = 0) => { const date = toDate(startDate); const countNeeded = parseInt(numberOfSessions, 10); if (!date || isNaN(countNeeded) || countNeeded < 1) return null; const validDays = normalizeWeekdays(days); if (!validDays.length) return null; let current = new Date(date); let count = 0; let lastMatchingDate = null; let safetyLimit = 365 * 5; while (count < countNeeded && safetyLimit > 0) { safetyLimit--; if (validDays.includes(current.getDay())) { count++; lastMatchingDate = new Date(current); } if (count >= countNeeded) break; current.setDate(current.getDate() + 1); } return lastMatchingDate; }; module.exports = { IRAN_WEEK_ORDER, PERSIAN_WEEKDAYS, formatCourseTime, formatClassDays, formatClassDaysFromIndexes, formatClassStartDate, normalizeWeekdays, normalizeClockTime, buildClassScheduleContext, calculateClassEndDate };