window.matchMedia = window.matchMedia || function () {
	return {
		matches: false,
		onchange: () => {}
	};
};

const { test } = require( '../../../resources/skins.vector.js/setupIntersectionObservers.js' );
const {
	STICKY_HEADER_EXPERIMENT_NAME
} = require( '../../../resources/skins.vector.js/stickyHeader.js' );
describe( 'main.js', () => {
	it( 'getHeadingIntersectionHandler', () => {
		const content = document.createElement( 'div' );
		content.setAttribute( 'class', 'mw-body-content' );
		content.setAttribute( 'id', 'mw-content-text' );
		const parserOutput = document.createElement( 'div' );
		parserOutput.setAttribute( 'class', 'mw-parser-output' );
		content.appendChild( parserOutput );

		const headingOld = document.createElement( 'h2' );
		const headlineOld = document.createElement( 'span' );
		headlineOld.classList.add( 'mw-headline' );
		headlineOld.setAttribute( 'id', 'headline-old' );
		headingOld.appendChild( headlineOld );
		parserOutput.appendChild( headingOld );

		const headingNew = document.createElement( 'div' );
		headingNew.classList.add( 'mw-heading' );
		const headlineNew = document.createElement( 'h2' );
		headlineNew.setAttribute( 'id', 'headline-new' );
		headingNew.appendChild( headlineNew );
		parserOutput.appendChild( headingNew );

		[
			[ content, 'toc-mw-content-text' ],
			[ headingOld, 'toc-headline-old' ],
			[ headingNew, 'toc-headline-new' ]
		].forEach( ( testCase ) => {
			const node = /** @type {HTMLElement} */ ( testCase[ 0 ] );
			const fn = jest.fn();
			const handler = test.getHeadingIntersectionHandler( fn );
			handler( node );
			expect( fn ).toHaveBeenCalledWith( testCase[ 1 ] );
		} );
	} );

	it( 'initStickyHeaderABTests', () => {
		const STICKY_HEADER_AB = {
			name: STICKY_HEADER_EXPERIMENT_NAME,
			enabled: true
		};
		[
			{
				abConfig: STICKY_HEADER_AB,
				isEnabled: false, // sticky header unavailable
				isUserInTreatmentBucket: false, // not in treatment bucket
				expectedResult: {
					showStickyHeader: false
				}
			},
			{
				abConfig: STICKY_HEADER_AB,
				isEnabled: true, // sticky header available
				isUserInTreatmentBucket: false, // not in treatment bucket
				expectedResult: {
					showStickyHeader: false
				}
			},
			{
				abConfig: STICKY_HEADER_AB,
				isEnabled: false, // sticky header is not available
				isUserInTreatmentBucket: true, // but the user is in the treatment bucket
				expectedResult: {
					showStickyHeader: false
				}
			},
			{
				abConfig: STICKY_HEADER_AB,
				isEnabled: true,
				isUserInTreatmentBucket: true,
				expectedResult: {
					showStickyHeader: true
				}
			}
		].forEach(
			( {
				abConfig,
				isEnabled,
				isUserInTreatmentBucket,
				expectedResult
			} ) => {
				document.documentElement.classList.add( 'vector-sticky-header-enabled' );
				const result = test.initStickyHeaderABTests(
					abConfig,
					// isStickyHeaderFeatureAllowed
					isEnabled,
					( experiment ) => ( {
						name: experiment.name,
						isInBucket: () => true,
						isInSample: () => true,
						getBucket: () => 'bucket',
						isInTreatmentBucket: () => isUserInTreatmentBucket
					} )
				);
				expect( result ).toMatchObject( expectedResult );
				// Check that there are no side effects
				expect(
					document.documentElement.classList.contains( 'vector-sticky-header-enabled' )
				).toBe( true );
			} );
	} );
} );

const sectionObserverFn = () => ( {
	pause: () => {},
	resume: () => {},
	mount: () => {},
	unmount: () => {},
	setElements: () => {},
	calcIntersection: () => {}
} );

describe( 'Table of contents re-rendering', () => {
	const mockMwHook = () => {
		/** @type {Object.<string, Function>} */
		const callback = {};
		jest.spyOn( mw, 'hook' ).mockImplementation( ( name ) => ( {
			add: function ( fn ) {
				callback[ name ] = fn;

				return this;
			},
			fire: ( data ) => {
				if ( callback[ name ] ) {
					callback[ name ]( data );
				}
			}
		} ) );
	};

	afterEach( () => {
		jest.restoreAllMocks();
	} );

	it( 'listens to wikipage.tableOfContents hook when mounted', () => {
		mockMwHook();
		const spy = jest.spyOn( mw, 'hook' );
		const tocElement = document.createElement( 'div' );
		const bodyContent = document.createElement( 'article' );
		const toc = test.setupTableOfContents( tocElement, bodyContent, sectionObserverFn );
		expect( toc ).not.toBe( null );
		expect( spy ).toHaveBeenCalledWith( 'wikipage.tableOfContents' );
		expect( spy ).not.toHaveBeenCalledWith( 'wikipage.tableOfContents.vector' );
	} );

	it( 'Firing wikipage.tableOfContents triggers reloadTableOfContents', async () => {
		mockMwHook();
		const tocElement = document.createElement( 'div' );
		const bodyContent = document.createElement( 'article' );
		const toc = test.setupTableOfContents( tocElement, bodyContent, sectionObserverFn );
		if ( !toc ) {
			// something went wrong
			expect( true ).toBe( false );
			return;
		}
		const spy = jest.spyOn( toc, 'reloadTableOfContents' ).mockImplementation( () => Promise.resolve() );

		mw.hook( 'wikipage.tableOfContents' ).fire( [
			// Add new section to see how the re-render performs.
			{
				toclevel: 1,
				number: '4',
				line: 'bat',
				anchor: 'bat',
				'is-top-level-section': true,
				'is-parent-section': false,
				'array-sections': null
			}
		] );

		expect( spy ).toHaveBeenCalled();
	} );
} );
