// eslint-disable-next-line n/no-missing-require
const { EditorView, Text } = require( 'ext.CodeMirror.lib' );
const CodeMirrorLint = require( '../../resources/codemirror.lint.js' );
const CodeMirrorGotoLine = require( '../../resources/codemirror.gotoLine.js' );

const cmLint = new CodeMirrorLint();
cmLint.view = new EditorView();
const { dom, update } = cmLint.panel;
const doc = Text.of( [ 'foo', 'bar' ] );
const apply = jest.fn();

const updateSelection = ( anchor, head ) => {
	update( {
		state: {
			doc,
			selection: { main: { anchor, head } }
		},
		transactions: [],
		selectionSet: true
	} );
};

describe( 'CodeMirrorLint', () => {
	beforeEach( () => {
		cmLint.diagnostics = CodeMirrorLint.renderDiagnostics( [
			{
				from: 0,
				to: 1,
				severity: 'error',
				message: 'Error message',
				actions: [
					{
						name: 'Fix',
						tooltip: 'tooltip',
						apply
					},
					{
						name: 'Suggestion',
						tooltip: 'tooltip',
						apply
					}
				]
			},
			{
				from: 0,
				to: 1,
				severity: 'warning',
				message: 'Warning message'
			},
			{
				from: 0,
				to: 1,
				severity: 'info',
				message: 'Info message'
			}
		] );
	} );

	it( 'should contain 3 parts', () => {
		expect( dom.childElementCount ).toEqual( 3 );
		expect( dom.firstChild.className ).toEqual( 'cm-mw-panel--status-worker' );
		expect( dom.firstChild.childElementCount ).toEqual( 3 );
		expect( dom.firstChild.firstChild.className ).toEqual( 'cm-mw-panel--status-error' );
		expect( dom.firstChild.firstChild.lastChild.textContent ).toEqual( '0' );
		expect( dom.firstChild.children[ 1 ].className ).toEqual( 'cm-mw-panel--status-warning' );
		expect( dom.firstChild.children[ 1 ].lastChild.textContent ).toEqual( '0' );
		expect( dom.firstChild.lastChild.className ).toEqual( 'cm-mw-panel--status-info' );
		expect( dom.firstChild.lastChild.lastChild.textContent ).toEqual( '0' );
		expect( dom.children[ 1 ].className ).toEqual( 'cm-mw-panel--status-message' );
		expect( dom.lastChild.className ).toEqual( 'cm-mw-panel--status-line' );
		expect( dom.lastChild.textContent ).toEqual( '1:0' );
	} );

	it( 'should update the diagnostics count', () => {
		const errorText = dom.querySelector( '.cm-mw-panel--status-error' ).lastChild;
		const warningText = dom.querySelector( '.cm-mw-panel--status-warning' ).lastChild;
		const infoText = dom.querySelector( '.cm-mw-panel--status-info' ).lastChild;
		cmLint.updateDiagnosticsCount( 'error', errorText );
		cmLint.updateDiagnosticsCount( 'warning', warningText );
		cmLint.updateDiagnosticsCount( 'info', infoText );
		expect( errorText.textContent ).toEqual( '1' );
		expect( warningText.textContent ).toEqual( '1' );
		expect( infoText.textContent ).toEqual( '1' );
	} );

	it( 'should update the diagnostic message', () => {
		const message = dom.querySelector( '.cm-mw-panel--status-message' );
		cmLint.updateDiagnosticMessage( 0, message );
		expect( message.textContent ).toEqual( 'Error messageFixSuggestion' );
		expect( message.querySelector( '.cm-diagnosticText-clickable' ) ).toBeNull();
		cmLint.updateDiagnosticMessage( 2, message );
		expect( message.textContent ).toEqual( '' );
		cmLint.updateDiagnosticMessage( 1, message );
		expect( message.textContent ).toEqual( 'Error messageFixSuggestion' );
		expect( message.querySelector( '.cm-diagnosticText-clickable' ) ).toBeNull();
		expect( message.querySelectorAll( 'button' ).length ).toEqual( 2 );
		for ( const button of message.querySelectorAll( 'button' ) ) {
			expect( button.title ).toEqual( 'tooltip' );
			button.click();
		}
		expect( apply ).toHaveBeenCalledTimes( 2 );
	} );

	it( 'should hide action buttons when read-only', () => {
		cmLint.diagnostics = CodeMirrorLint.renderDiagnostics( [
			{
				from: 0,
				to: 1,
				severity: 'error',
				message: 'Error message',
				actions: [
					{
						name: 'Fix',
						tooltip: 'tooltip',
						apply
					},
					{
						name: 'Suggestion',
						tooltip: 'tooltip',
						apply
					}
				]
			}
		], true );
		const message = dom.querySelector( '.cm-mw-panel--status-message' );
		cmLint.updateDiagnosticMessage( 1, message );
		expect( message.textContent ).toEqual( 'Error message' );
		expect( message.querySelector( '.cm-diagnosticText-clickable' ) ).toBeNull();
		expect( message.querySelectorAll( 'button' ).length ).toEqual( 0 );
	} );

	it( 'should update the position/selection', () => {
		const line = dom.lastChild;
		updateSelection( 1, 1 );
		expect( line.textContent ).toEqual( '1:1' );
		updateSelection( 1, 6 );
		expect( line.textContent ).toEqual( '2:2|(1:1)' );
		updateSelection( 5, 2 );
		expect( line.textContent ).toEqual( '1:2|(1:0)' );
	} );

	it( 'should open the goto line panel when clicking on status line', () => {
		const gotoLine = new CodeMirrorGotoLine();
		cmLint.gotoLine = gotoLine;
		cmLint.view = new EditorView();
		expect( gotoLine.input ).toBeUndefined();
		dom.querySelector( '.cm-mw-panel--status-line' ).click();
		expect( gotoLine.input ).toBeDefined();
		expect( gotoLine.view.state.field( gotoLine.panelStateField ) ).toBeDefined();
	} );
} );
