// Not sure why the /// <referennce ... /> is needed, but tsc fails without it
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference path="../node_modules/@types/node/fs.d.ts" />
import { promises as fs } from 'node:fs';
import { fileURLToPath } from 'node:url';
import ms from 'ms';
import { allPass, compose, not, range } from 'rambda';
import AL from 'await-lock';
import { HTTPError } from './scraper/network/http-error.js';
import { oneDayInMs } from '../shared/utils.js';
export { chunkArray } from '../shared/utils.js';
export const pastDate = (past) => {
    if (!past)
        return new Date();
    const d = new Date();
    d.setMilliseconds(d.getMilliseconds() - ms(past));
    return d;
};
export const isAfter = (time) => (date) => date.getTime() > pastDate(time).getTime();
export const isWithin = (time) => (date) => date.getTime() <= pastDate(time).getTime();
export const isNewerThan = (date1) => (date2) => date2.getTime() > date1.getTime();
export const shortDateFormat = (date) => [date.toLocaleString('default', { month: 'short' }), date.getDate()].join(' ');
export const isMaster = (branchName) => ['refs/heads/master', 'refs/heads/main'].includes(branchName);
export const normalizeBranchName = (branchName) => branchName.replace('refs/heads/', '');
export const doesFileExist = async (filePath) => {
    try {
        await fs.access(filePath);
        return true;
    }
    catch (_a) {
        return false;
    }
};
export const unique = (xs) => [...new Set(xs)];
const weekNumbers = [12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
export const weekLimits = weekNumbers.map(weekNumber => [
    pastDate(`${weekNumber * 7} days`),
    pastDate(`${(weekNumber - 1) * 7} days`),
]);
export const weeks = weekNumbers.map(weekNumber => allPass([
    isAfter(`${weekNumber * 7} days`),
    compose(not, isAfter(`${(weekNumber - 1) * 7} days`)),
]));
export const mapSettleSeries = (xs, fn) => xs.reduce((acc, x) => acc.then(accArr => fn(x)
    .then(value => ({ status: 'fulfilled', value }))
    .catch(error => ({ status: 'rejected', reason: error }))
    .then(result => [...accArr, result])), Promise.resolve([]));
export const invokeSeries = (xs, fn) => xs.reduce((acc, x, index) => acc.then(previous => fn(x, previous, index)), 
// eslint-disable-next-line unicorn/no-useless-undefined
Promise.resolve(undefined));
export const startTimer = () => {
    const start = Date.now();
    return () => `${(Date.now() - start) / 1000}s`;
};
export const queryPeriodDays = (config) => Math.round((Date.now() - config.azure.queryFrom.getTime()) / (1000 * 60 * 60 * 24));
export const wait = (ms) => new Promise(resolve => {
    setTimeout(resolve, ms);
});
export const retry = (fn, { retryCount = 10, waitTime = 1 } = {}) => fn().catch(async (error) => {
    if (retryCount <= 0)
        throw error;
    if (error instanceof HTTPError && error.status >= 400 && error.status < 500) {
        throw error;
    }
    await wait(waitTime * 1000);
    return retry(fn, { retryCount: retryCount - 1, waitTime });
});
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore-error CJS interop
const AwaitLock = AL.default;
export const lock = () => {
    const lock = new AwaitLock();
    const acquireLock = lock.acquireAsync.bind(lock);
    const releaseLock = lock.release.bind(lock);
    return [acquireLock, releaseLock];
};
export const dirname = (importMetaUrl) => fileURLToPath(new URL('.', importMetaUrl));
export const splitDateRangeByDays = (days) => (startDate, endDate) => {
    const start = new Date(startDate);
    const end = new Date(endDate);
    const numberOfIntervals = Math.floor((end.getTime() - start.getTime()) / (days * oneDayInMs)) + 1;
    return range(1, numberOfIntervals).map(intervalIndex => {
        const intervalStart = new Date(start.getTime() + intervalIndex * days * oneDayInMs);
        return intervalStart.toISOString().split('T')[0];
    });
};
export const splitDateRangeByWeek = splitDateRangeByDays(7);
export const createIntervals = (startDate, endDate) => {
    const numberOfDays = (endDate.getTime() - startDate.getTime()) / oneDayInMs;
    return {
        numberOfDays,
        numberOfIntervals: Math.floor(numberOfDays / 7 + (numberOfDays % 7 === 0 ? 0 : 1)),
    };
};
