import { useEffect, useRef, useState } from '@wordpress/element';
import type { AdminRecord } from '../../admin-data';
import type { DesignSystemViewModel } from '../types';

export interface LaunchDetailState {
	detail: AdminRecord | null;
	loading: boolean;
	error: string;
}

// Module-level cache shared across hook instances: detail is fetched at most
// once per UUID, in-flight requests are deduped, and stale results ignored.
const detailCache = new Map< string, AdminRecord >();
const inFlight = new Map< string, Promise< AdminRecord > >();
const AJAX_LAUNCH_DETAIL = 'scheduled_changes_admin_launch_detail';

const requestDetail = (
	model: DesignSystemViewModel,
	uuid: string
): Promise< AdminRecord > => {
	const cached = detailCache.get( uuid );
	if ( cached ) {
		return Promise.resolve( cached );
	}

	const pending = inFlight.get( uuid );
	if ( pending ) {
		return pending;
	}

	const url =
		`${ model.actions.ajaxUrl }?action=${ AJAX_LAUNCH_DETAIL }` +
		`&nonce=${ encodeURIComponent( model.actions.nonce ) }` +
		`&uuid=${ encodeURIComponent( uuid ) }`;

	const promise = window
		.fetch( url, { credentials: 'same-origin' } )
		.then( ( response ) => response.json() )
		.then( ( payload ) => {
			const detail = ( payload?.data ?? payload ) as AdminRecord;
			detailCache.set( uuid, detail );
			inFlight.delete( uuid );
			return detail;
		} )
		.catch( ( reason ) => {
			inFlight.delete( uuid );
			throw reason;
		} );

	inFlight.set( uuid, promise );
	return promise;
};

/**
 * Lazy launch-detail loader. The list/read-model renders from the bootstrap;
 * this hook only fetches when a UUID is selected, caches by UUID, dedupes
 * in-flight requests, and ignores results for a UUID that is no longer selected.
 * @param model
 * @param uuid
 */
export const useLaunchDetail = (
	model: DesignSystemViewModel,
	uuid: string
): LaunchDetailState => {
	const [ state, setState ] = useState< LaunchDetailState >( {
		detail: null,
		loading: false,
		error: '',
	} );
	const activeUuid = useRef( uuid );
	activeUuid.current = uuid;

	useEffect( () => {
		if ( ! uuid || 'function' !== typeof window.fetch ) {
			setState( { detail: null, loading: false, error: '' } );
			return;
		}

		const cached = detailCache.get( uuid );
		if ( cached ) {
			setState( { detail: cached, loading: false, error: '' } );
			return;
		}

		setState( { detail: null, loading: true, error: '' } );

		requestDetail( model, uuid )
			.then( ( detail ) => {
				if ( activeUuid.current === uuid ) {
					setState( { detail, loading: false, error: '' } );
				}
			} )
			.catch( () => {
				if ( activeUuid.current === uuid ) {
					setState( {
						detail: null,
						loading: false,
						error: 'Could not load launch details.',
					} );
				}
			} );
	}, [ model, uuid ] );

	return state;
};
