const MILLISECONDS_PER_DAY = 24 * 60 * 60 * 1000;

export function academicCalendarWeekNumber(academicYearStartIso, dateIso) {
    const academicYearStart = parseIsoDate(academicYearStartIso);
    const date = parseIsoDate(dateIso);
    const daysFromYearStart = (date.timestamp - academicYearStart.timestamp) / MILLISECONDS_PER_DAY;

    if (!Number.isInteger(daysFromYearStart) || daysFromYearStart < 0) {
        throw new RangeError('Дата ячейки не может быть раньше начала учебного года');
    }

    const daysBeforeYearStartInFirstWeek = academicYearStart.dayOfWeek - 1;
    return Math.floor((daysBeforeYearStartInFirstWeek + daysFromYearStart) / 7) + 1;
}

function parseIsoDate(value) {
    const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(String(value));
    if (!match) {
        throw new TypeError('Ожидалась дата в формате ГГГГ-ММ-ДД');
    }

    const [, yearText, monthText, dayText] = match;
    const year = Number(yearText);
    const month = Number(monthText);
    const day = Number(dayText);
    const timestamp = Date.UTC(year, month - 1, day);
    const date = new Date(timestamp);
    if (date.getUTCFullYear() !== year
        || date.getUTCMonth() !== month - 1
        || date.getUTCDate() !== day) {
        throw new TypeError('Ожидалась дата в формате ГГГГ-ММ-ДД');
    }

    const jsDayOfWeek = date.getUTCDay();
    return {
        timestamp,
        dayOfWeek: jsDayOfWeek === 0 ? 7 : jsDayOfWeek
    };
}
