export interface DeliverySettings {
	frequency_cap: number;
	dismissal_snooze: 'session' | 'day' | 'week';
	repeat_protection: boolean;
	cross_page_pacing: boolean;
	optimized_loading: boolean;
	data_saver: boolean;
}

const viewsKey = 'voidpulse-delivery-views';
const repeatKey = 'voidpulse-delivery-shown';
const nextKey = 'voidpulse-delivery-next';
const snoozeKey = 'voidpulse-delivery-snooze';
const sessionSnoozeKey = 'voidpulse-delivery-session-snooze';

function safeStorage( type: 'localStorage' | 'sessionStorage' ) {
	try {
		return window[ type ];
	} catch ( error ) {
		return null;
	}
}

function numberList( storage: Storage | null, key: string ) {
	try {
		const parsed = JSON.parse( storage?.getItem( key ) || '[]' );
		return Array.isArray( parsed )
			? parsed.filter( ( value ) => Number.isFinite( Number( value ) ) )
			: [];
	} catch ( error ) {
		return [];
	}
}

function stringList( storage: Storage | null, key: string ) {
	try {
		const parsed = JSON.parse( storage?.getItem( key ) || '[]' );
		return Array.isArray( parsed )
			? parsed.filter( ( value ) => 'string' === typeof value )
			: [];
	} catch ( error ) {
		return [];
	}
}

export function createDeliveryController( settings: DeliverySettings ) {
	const localStore = safeStorage( 'localStorage' );
	const sessionStore = safeStorage( 'sessionStorage' );
	const requestedCap = Number( settings.frequency_cap );
	const cap =
		requestedCap <= 0
			? Number.POSITIVE_INFINITY
			: Math.min( 50, Math.max( 1, requestedCap ) );

	function nextDisplayDelay( identity = '' ): number | null {
		try {
			if ( '1' === sessionStore?.getItem( sessionSnoozeKey ) ) {
				return null;
			}
			if (
				settings.repeat_protection &&
				identity &&
				stringList( sessionStore, repeatKey ).includes( identity )
			) {
				return null;
			}
		} catch ( error ) {}
		const now = Date.now();
		try {
			const snoozeUntil = Number( localStore?.getItem( snoozeKey ) || 0 );
			if ( snoozeUntil > now ) {
				return Math.max( 0.05, ( snoozeUntil - now ) / 1000 );
			}
		} catch ( error ) {}
		const cutoff = now - 30 * 60 * 1000;
		const views = numberList( localStore, viewsKey )
			.filter( ( timestamp ) => Number( timestamp ) >= cutoff )
			.sort( ( left, right ) => Number( left ) - Number( right ) );
		if ( Number.isFinite( cap ) && views.length >= cap ) {
			const releaseAt =
				Number( views[ views.length - cap ] ) + 30 * 60 * 1000;
			return Math.max( 0.05, ( releaseAt - now ) / 1000 );
		}
		try {
			const pacedUntil = settings.cross_page_pacing
				? Number( localStore?.getItem( nextKey ) || 0 )
				: 0;
			if ( pacedUntil > now ) {
				return Math.max( 0.05, ( pacedUntil - now ) / 1000 );
			}
		} catch ( error ) {
			return 0;
		}
		return 0;
	}

	function canDisplay( identity = '' ) {
		return 0 === nextDisplayDelay( identity );
	}

	function recordDisplay( identity = '', duration = 0, gap = 0 ) {
		const now = Date.now();
		const cutoff = now - 30 * 60 * 1000;
		const views = numberList( localStore, viewsKey )
			.filter( ( timestamp ) => Number( timestamp ) >= cutoff )
			.concat( now )
			.slice( -50 );
		try {
			localStore?.setItem( viewsKey, JSON.stringify( views ) );
			if ( settings.cross_page_pacing ) {
				localStore?.setItem(
					nextKey,
					String( now + 1000 * Math.max( 0, duration + gap ) )
				);
			}
			if ( settings.repeat_protection && identity ) {
				const shown = stringList( sessionStore, repeatKey );
				if ( ! shown.includes( identity ) ) {
					sessionStore?.setItem(
						repeatKey,
						JSON.stringify( shown.concat( identity ).slice( -200 ) )
					);
				}
			}
		} catch ( error ) {}
	}

	function snooze() {
		try {
			if ( 'session' === settings.dismissal_snooze ) {
				sessionStore?.setItem( sessionSnoozeKey, '1' );
				return;
			}
			const duration =
				'week' === settings.dismissal_snooze
					? 7 * 24 * 60 * 60 * 1000
					: 24 * 60 * 60 * 1000;
			localStore?.setItem( snoozeKey, String( Date.now() + duration ) );
		} catch ( error ) {}
	}

	function setNextDelay( seconds: number ) {
		if ( ! settings.cross_page_pacing ) {
			return;
		}
		try {
			localStore?.setItem(
				nextKey,
				String( Date.now() + 1000 * Math.max( 0, seconds ) )
			);
		} catch ( error ) {}
	}

	function initialDelay( configuredSeconds: number ) {
		if ( ! settings.cross_page_pacing ) {
			return configuredSeconds;
		}
		try {
			const remaining = Math.max(
				0,
				Number( localStore?.getItem( nextKey ) || 0 ) - Date.now()
			);
			return Math.max( configuredSeconds, remaining / 1000 );
		} catch ( error ) {
			return configuredSeconds;
		}
	}

	function defer( callback: () => void ) {
		if ( settings.optimized_loading && window.requestIdleCallback ) {
			window.requestIdleCallback( callback, { timeout: 2000 } );
			return;
		}
		callback();
	}

	function allowImages() {
		return ! (
			settings.data_saver && Boolean( navigator.connection?.saveData )
		);
	}

	return {
		allowImages,
		canDisplay,
		defer,
		initialDelay,
		nextDisplayDelay,
		recordDisplay,
		setNextDelay,
		snooze,
	};
}
