/**
 * Helpers for the countdown extension.
 */

/**
 * Calculates and manages the end date for an evergreen countdown timer.
 *
 * @since x.x.x
 *
 * @param {number} [days=0]           Number of days to add to the timer.
 * @param {number} [hours=0]          Number of hours to add to the timer.
 * @param {number} [minutes=0]        Number of minutes to add to the timer.
 * @param {string} [uniqueId='']      Unique identifier for the timer instance.
 * @param {number} [resetAfterDays=1] Number of days after which the timer should reset (1 for immediate reset).
 * @return {string|null} ISO string of the end date if valid, null otherwise.
 */
export const getEvergreenEndDate = ( days = 0, hours = 0, minutes = 0, uniqueId = '', resetAfterDays = 1 ) => {
	// If no uniqueId is provided, return null.
	if ( ! uniqueId ) {
		return null; // Invalid uniqueId
	}

	const END_KEY = getEndKey( uniqueId );
	const START_KEY = getStartKey( uniqueId );

	// Retrieve stored end date and start time from cookies.
	const storedEndDate = getCookie( END_KEY );
	const storedStartTime = getCookie( START_KEY );

	if ( storedEndDate && storedStartTime ) {
		const endDate = new Date( storedEndDate );
		const startTime = new Date( storedStartTime );
		const now = new Date();

		// If end date is valid and not expired, return it.
		if ( ! isNaN( endDate.getTime() ) && endDate > now ) {
			return storedEndDate;
		}

		// End date has expired or is invalid.
		// Check reset period for positive resetAfterDays.
		if ( resetAfterDays > 0 ) {
			const resetMs = resetAfterDays * 24 * 60 * 60 * 1000;
			if ( now.getTime() - startTime.getTime() < resetMs ) {
				// Reset period not elapsed, keep expired state
				return storedEndDate;
			}
		}

		// Reset immediately if resetAfterDays is 0 and timer is expired, or if reset period has elapsed.
		resetEvergreenCookies( uniqueId );
	}

	// Calculate total duration in milliseconds.
	const durationMs = ( days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60 ) * 1000;

	// If duration is 0 or negative, return null.
	if ( durationMs <= 0 ) {
		return null;
	}

	// Calculate new end date
	const now = new Date();
	const newDate = new Date( now.getTime() + durationMs );

	// Set cookie expiration (use resetAfterDays if set, otherwise a default, 1 days).
	const cookieExpirationDays = resetAfterDays > 0 ? resetAfterDays : 1;

	// Store new end date and start time in cookies
	const endDateStr = newDate.toISOString().replace( /\.\d{3}Z$/, 'Z' );
	setCookie( END_KEY, endDateStr, cookieExpirationDays );
	setCookie( START_KEY, now.toISOString(), cookieExpirationDays );

	return endDateStr;
};

/**
 * Sets a cookie with the given name, value, and expiration days.
 *
 * @since x.x.x
 *
 * @param {string} name  Name of the cookie.
 * @param {string} value Value to store in the cookie.
 * @param {number} days  Number of days until the cookie expires.
 * @return {void}
 */
export const setCookie = ( name, value, days ) => {
	const date = new Date();
	date.setTime( date.getTime() + days * 24 * 60 * 60 * 1000 );
	const expires = `expires=${ date.toUTCString() }`;
	document.cookie = `${ name }=${ encodeURIComponent( value ) }; ${ expires }; path=/; SameSite=Strict`;
};

/**
 * Retrieves the value of a cookie by name.
 *
 * @since x.x.x
 *
 * @param {string} name Name of the cookie to retrieve.
 * @return {string|null} The cookie value if found, null otherwise.
 */
export const getCookie = ( name ) => {
	const nameEQ = `${ name }=`;
	const cookies = document.cookie.split( ';' );
	for ( let cookie of cookies ) {
		cookie = cookie.trim();
		if ( cookie.indexOf( nameEQ ) === 0 ) {
			return decodeURIComponent( cookie.substring( nameEQ.length ) );
		}
	}
	return null;
};

/**
 * Deletes a cookie by setting its expiration date in the past.
 *
 * @since x.x.x
 *
 * @param {string} name Name of the cookie to delete.
 * @return {void}
 */
export const deleteCookie = ( name ) => {
	document.cookie = `${ name }=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Strict`;
};

/**
 * Generates the cookie key for storing an evergreen timer's end date.
 *
 * @since x.x.x
 *
 * @param {string} uniqueId Unique identifier for the timer instance.
 * @return {string} Formatted cookie key string.
 */
export const getEndKey = ( uniqueId ) => {
	return `spectra_countdown_evergreen_end_${ uniqueId }`;
};

/**
 * Generates the cookie key for storing an evergreen timer's start time.
 *
 * @since x.x.x
 *
 * @param {string} uniqueId Unique identifier for the timer instance.
 * @return {string} Formatted cookie key string.
 */
export const getStartKey = ( uniqueId ) => {
	return `spectra_countdown_evergreen_start_${ uniqueId }`;
};

/**
 * Resets all cookies associated with an evergreen timer.
 *
 * @since x.x.x
 *
 * @param {string} uniqueId Unique identifier for the timer instance.
 * @return {void}
 */
export const resetEvergreenCookies = ( uniqueId ) => {
	deleteCookie( getEndKey( uniqueId ) );
	deleteCookie( getStartKey( uniqueId ) );
};

/**
 * Validates whether a given string is a valid URL.
 *
 * @since x.x.x
 *
 * @param {string} url The URL string to validate.
 * @return {boolean} True if the URL is valid, false otherwise.
 */
export const isValidURL = ( url ) => {
	try {
		new URL( url );
		return true;
	} catch ( e ) {
		return false;
	}
};
