import Mathematics from '../src/math.js';
import AutoMath from '../src/automath.js';
import { ClassicEditor, Clipboard, Paragraph, Undo, Typing, getData, setData } from 'ckeditor5';
import { expect } from 'chai';
import type { SinonFakeTimers } from 'sinon';
import { describe, beforeEach, it, afterEach } from "vitest";
describe( 'AutoMath - integration', () => {
	let editorElement: HTMLDivElement, editor: ClassicEditor;
	beforeEach( async () => {
		editorElement = document.createElement( 'div' );
		document.body.appendChild( editorElement );
		return ClassicEditor
			.create( editorElement, {
				plugins: [ Mathematics, AutoMath, Typing, Paragraph ],
				licenseKey: "GPL",
				math: {
					engine: ( equation, element, display ) => {
						if ( display ) {
							element.innerHTML = '\\[' + equation + '\\]';
						} else {
							element.innerHTML = '\\(' + equation + '\\)';
						}
					}
				}
			} )
			.then( newEditor => {
				editor = newEditor;
			} );
	} );
	afterEach( () => {
		editorElement.remove();
		return editor.destroy();
	} );
	it( 'should load Clipboard plugin', () => {
		expect( editor.plugins.get( Clipboard ) ).to.instanceOf( Clipboard );
	} );
	it( 'should load Undo plugin', () => {
		expect( editor.plugins.get( Undo ) ).to.instanceOf( Undo );
	} );
	it( 'has proper name', () => {
		expect( AutoMath.pluginName ).to.equal( 'AutoMath' );
	} );
	describe( 'use fake timers', () => {
		let clock: SinonFakeTimers;
		beforeEach( () => {
			clock = sinon.useFakeTimers();
		} );
		afterEach( () => {
			clock.restore();
		} );
		it( 'replaces pasted text with mathtex element after 100ms', () => {
			setData( editor.model, '[]' );
			pasteHtml( editor, '\\[x^2\\]' );
			expect( getData( editor.model ) ).to.equal(
				'\\[x^2\\][]'
			);
			clock.tick( 100 );
			expect( getData( editor.model ) ).to.equal(
				'[]'
			);
		} );
		it( 'replaces pasted text with inline mathtex element after 100ms', () => {
			setData( editor.model, '[]' );
			pasteHtml( editor, '\\(x^2\\)' );
			expect( getData( editor.model ) ).to.equal(
				'\\(x^2\\)[]'
			);
			clock.tick( 100 );
			expect( getData( editor.model ) ).to.equal(
				'[]'
			);
		} );
		it( 'can undo auto-mathing', () => {
			setData( editor.model, '[]' );
			pasteHtml( editor, '\\[x^2\\]' );
			expect( getData( editor.model ) ).to.equal(
				'\\[x^2\\][]'
			);
			clock.tick( 100 );
			editor.commands.execute( 'undo' );
			expect( getData( editor.model ) ).to.equal(
				'\\[x^2\\][]'
			);
		} );
		it( 'works for not collapsed selection inside single element', () => {
			setData( editor.model, '[Foo]' );
			pasteHtml( editor, '\\[x^2\\]' );
			clock.tick( 100 );
			expect( getData( editor.model ) ).to.equal(
				'[]'
			);
		} );
		it( 'works for not collapsed selection over a few elements', () => {
			setData( editor.model, 'Fo[oBa]r' );
			pasteHtml( editor, '\\[x^2\\]' );
			clock.tick( 100 );
			expect( getData( editor.model ) ).to.equal(
				'Fo[]r'
			);
		} );
		it( 'inserts mathtex in-place (collapsed selection)', () => {
			setData( editor.model, 'Foo []Bar' );
			pasteHtml( editor, '\\[x^2\\]' );
			clock.tick( 100 );
			expect( getData( editor.model ) ).to.equal(
				'Foo ' +
				'[]' +
				'Bar'
			);
		} );
		it( 'inserts math in-place (non-collapsed selection)', () => {
			setData( editor.model, 'Foo [Bar] Baz' );
			pasteHtml( editor, '\\[x^2\\]' );
			clock.tick( 100 );
			expect( getData( editor.model ) ).to.equal(
				'Foo ' +
				'[]' +
				' Baz'
			);
		} );
		it( 'does nothing if pasted two equation as text', () => {
			setData( editor.model, '[]' );
			pasteHtml( editor, '\\[x^2\\] \\[\\sqrt{x}2\\]' );
			clock.tick( 100 );
			expect( getData( editor.model ) ).to.equal(
				'\\[x^2\\] \\[\\sqrt{x}2\\][]'
			);
		} );
	} );
	function pasteHtml( editor: ClassicEditor, html: string ) {
		editor.editing.view.document.fire( 'paste', {
			dataTransfer: createDataTransfer( { 'text/html': html } ),
			preventDefault() {
				return undefined;
			}
		} );
	}
	function createDataTransfer( data: Record ) {
		return {
			getData( type: string ) {
				return data[ type ];
			}
		};
	}
} );