/* eslint capitalized-comments: "off" */
/**
 * Format a date according to localized custom
 * @param {Date|string} d The date to convert
 * @param {boolean} short Short format (default false)
 * @returns {string}
 */
export function formatDate(d, short) {
    if (!(d instanceof Date)) {
        if (typeof d == 'number') {
            d *= 1000; // Convert from seconds to milliseconds.
        }
        d = new Date(d);
    }

    let monthformat = "short";
    if (short === true) {
        monthformat = "numeric";
    } else if (short === false) {
        monthformat = "long";
    }
    return d.toLocaleDateString(document.documentElement.lang, {
        year: 'numeric', month: monthformat, day: 'numeric'
    });
}

/**
 * Format a date according to localized custom
 * @param {Date|string} d The date to convert
 * @param {boolean} short Short format (default false)
 * @returns {string}
 */
export function formatDatetime(d, short) {
    if (!(d instanceof Date)) {
        if (typeof d == 'number') {
            d *= 1000; // Convert from seconds to milliseconds.
        }
        d = new Date(d);
    }

    let monthformat = "short";
    if (short === true) {
        monthformat = "numeric";
    } else if (short === false) {
        monthformat = "long";
    }
    return d.toLocaleDateString(document.documentElement.lang, {
        year: 'numeric', month: monthformat, day: 'numeric'
    }) + " " + d.toLocaleTimeString(document.documentElement.lang, {
        timeStyle: "short",
    });
}

/**
 * Provides standardized information about the period between two dates
 * As
 * @param {Date|string} first First day of the span
 * @param {Date|string} last Last day of the span
 * @returns {Object} Object containing formatted start and end dates and span information
 */
export function datespaninfo(first, last) {
    if (!(first instanceof Date)) {
        first = new Date(first);
    }
    if (!(last instanceof Date)) {
        last = new Date(last);
    }

    // Make sure the end date is at the very end of the day and the start date at the very beginning
    first.setHours(0);
    first.setMinutes(0);
    first.setSeconds(0);
    first.setMilliseconds(0);
    last.setHours(23);
    last.setMinutes(59);
    last.setSeconds(59);
    last.setMilliseconds(999);

    const dayspan = Math.round(((last - first) + 1) / (24 * 60 * 60 * 1000)); // Add one millisecond to offset the 999 ms
    const years = Math.floor(dayspan / 365); // Yes, we ignore leap years/leap days
    const ydaysleft = dayspan % 365;

    const weeks = Math.floor(ydaysleft / 7);
    const wdaysleft = ydaysleft % 7;

    return {
        first: first,
        last: last,
        totaldays: dayspan,
        years: years,
        weeks: weeks,
        days: wdaysleft,
        formatted: {
            first: formatDate(first),
            last: formatDate(last),
        }
    };

}

/**
 * Format a Date object to YYYY-MM-DD format
 * @param {Date} date Date object
 * @returns {String} Date string in YYYY-MM-DD format
 */
function dateYYYYMMDD(date) {
    const d = new Date(date);
    let month = '' + (d.getMonth() + 1);
    let day = '' + d.getDate();
    const year = d.getFullYear();

    if (month.length < 2) {
        month = '0' + month;
    }
    if (day.length < 2) {
        day = '0' + day;
    }
    return [year, month, day].join('-');
}

/**
 * String formatting function - replaces {name} in string by value of same key in values parameter
 * @param {string} datestr String containing date format in YYYY-MM-DD
 * @param {int} days Object containing keys to replace {key} strings with. Make negative to subtract
 * @returns {String} Date string in YYYY-MM-DD format
 */
export function addDays(datestr, days) {
    const date = new Date(datestr);
    const newdate = new Date(date.getTime() + (days * 86400000)); // Add n days in ms.
    return dateYYYYMMDD(newdate);
}

/**
 * Determine start and end dates of a studyplan
 * @param {*} plan
 * @returns {object}
 */
export function studyplanDates(plan) {
    let earliestStart = null;
    let latestEnd = null;
    let openEnded = false;

    for (const ix in plan.pages) {
        const page = plan.pages[ix];
        const s = new Date(page.startdate);
        if (!page.enddate) {
            openEnded = true; // One of the pages has no end date set...
        }

        if (!earliestStart || s < earliestStart) {
            earliestStart = s;
        }

        if (page.enddate) {
            const e = new Date(page.enddate);
            if (!latestEnd || e > latestEnd) {
                latestEnd = e;
            }
        }
    }
    return {
        start: earliestStart,
        end: (openEnded) ? null : latestEnd,
    };
}

/**
 * Determine past/present/future for a studyplan
 * @param {*} plan
 * @returns {string} one of 'past', 'present', 'future'
 */
export function studyplanTiming(plan) {
    const now = new Date().getTime();

    // If timeless or no timing info is available, all plans are present
    if (!plan.pages && plan.pages.length == 0 || (plan.pages[0] && plan.pages[0].timeless)) {
        return 'present';
    }

    const dates = studyplanDates(plan);

    if (dates.start < now) {
        if (dates.end && now > dates.end) {
            return 'past';
        } else {
            return 'present';
        }
    } else {
        return 'future';
    }
}

/**
 * Determine past/present/future for a studyplan
 * @param {*} page
 * @returns {string} one of 'past', 'present', 'future'
 */
export function studyplanPageTiming(page) {
    const now = new Date().getTime();

    if (page.timeless) {
        return "present";
    }
    const start = new Date(page.startdate);
    const end = (page.enddate) ? (new Date(page.enddate)) : null;

    if (start < now) {
        if (end && now > end) {
            return 'past';
        } else {
            return 'present';
        }
    } else {
        return 'future';
    }
}