/** @vitest-environment jsdom */
/**
 * The wiring between the CMP signal and the recorder.
 *
 * replay.test.ts proves what `applyConsentDecision` does. This proves the widget
 * actually calls it — the half that was missing, and the half no unit test of
 * the replay module can catch: a shopper who opened the modal before the banner
 * was answered and then accepted was never recorded, because the only code that
 * could have started the recorder ran on modal open and had already decided.
 */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, cleanup, waitFor } from '@testing-library/react';
import { App } from './App';
import { applyConsentDecision } from './replay';
import type { WidgetConfig } from './types';

vi.mock('./replay', () => ({
	applyConsentDecision: vi.fn().mockResolvedValue( undefined ),
	startReplay: vi.fn().mockResolvedValue( undefined ),
	stopReplay: vi.fn(),
	revokeReplay: vi.fn(),
	MODAL_OVERLAY_CLASS: 'aisthetix-modal-overlay',
} ) );

const config = {
	apiBaseUrl: 'https://brain.example.com',
	publishableKey: 'pk_test',
	productImage: 'https://cdn.example.com/shirt.jpg',
	productTitle: 'Linen Shirt',
	productId: '555',
	variantId: '111',
	locale: 'en',
	analytics: {
		replayKey: 'phc_browser',
		ingestHost: 'https://ingest.aisthetix.fyi',
		replayEnabled: true,
		environment: 'staging',
		storeId: 'store_1',
	},
} as unknown as WidgetConfig;

beforeEach( () => {
	localStorage.clear();
	sessionStorage.clear();
	document.body.innerHTML = '';
	vi.mocked( applyConsentDecision ).mockClear();
} );

afterEach( () => {
	cleanup();
	document.body.innerHTML = '';
} );

/** The decision the bootstrap announces after reading the merchant's CMP. */
function announceConsent( productAnalytics: boolean ) {
	document.dispatchEvent(
		new CustomEvent( 'aisthetix:consent-changed', { detail: { productAnalytics } } )
	);
}

describe( 'a CMP decision collected while the widget is mounted', () => {
	it( 'is handed to the recorder as a grant', async () => {
		render( <App config={ config } /> );

		announceConsent( true );

		await waitFor( () => expect( applyConsentDecision ).toHaveBeenCalled() );
		expect(
			vi.mocked( applyConsentDecision ).mock.calls[ 0 ][ 0 ],
			'a grant must reach the recorder'
		).toBe( true );
	} );

	it( 'is handed to the recorder as a withdrawal', async () => {
		render( <App config={ config } /> );

		announceConsent( false );

		await waitFor( () => expect( applyConsentDecision ).toHaveBeenCalled() );
		expect( vi.mocked( applyConsentDecision ).mock.calls[ 0 ][ 0 ] ).toBe( false );
	} );
} );
