// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { assert } from 'chai';
import sinon from 'sinon';
import * as Common from '../../core/common/common.js';
import * as Host from '../../core/host/host.js';
import * as SDK from '../../core/sdk/sdk.js';
import { createTarget, registerNoopActions, } from '../../testing/EnvironmentHelpers.js';
import { describeWithMockConnection, dispatchEvent, } from '../../testing/MockConnection.js';
import * as TextEditor from '../../ui/components/text_editor/text_editor.js';
import * as UI from '../../ui/legacy/legacy.js';
import * as Console from './console.js';
function compileScriptResponse(exception) {
    const exceptionDetails = exception ? { exception: { description: exception } } : undefined;
    return { exceptionDetails, getError: () => { } };
}
describeWithMockConnection('ConsoleContextSelector', () => {
    let target;
    let consolePrompt;
    let evaluateOnTarget;
    let compileScript;
    let editor;
    beforeEach(() => {
        sinon.stub(Host.AidaClient.HostConfigTracker.instance(), 'pollAidaAvailability').callsFake(async () => { });
        sinon.stub(Host.AidaClient.AidaClient, 'checkAccessPreconditions')
            .resolves("available" /* Host.AidaClient.AidaAccessPreconditions.AVAILABLE */);
        registerNoopActions(['console.clear', 'console.clear.history', 'console.create-pin']);
        consolePrompt = new Console.ConsolePrompt.ConsolePrompt();
        editor = consolePrompt.element.querySelector('devtools-text-editor');
        setCodeMirrorContent('foo');
        target = createTarget();
        const targetContext = createExecutionContext(target);
        UI.Context.Context.instance().setFlavor(SDK.RuntimeModel.ExecutionContext, targetContext);
        evaluateOnTarget = sinon.stub(target.runtimeAgent(), 'invoke_evaluate');
        compileScript = sinon.stub(target.runtimeAgent(), 'invoke_compileScript').resolves(compileScriptResponse());
        Common.Settings.Settings.instance().createSetting('ai-code-completion-enabled', false);
    });
    let id = 0;
    function createExecutionContext(target) {
        ++id;
        dispatchEvent(target, 'Runtime.executionContextCreated', {
            context: {
                id: id,
                origin: 'http://example.com',
                name: `c${id}`,
                uniqueId: `c${id}`,
                auxData: {
                    frameId: 'f2',
                },
            },
        });
        const runtimeModel = target.model(SDK.RuntimeModel.RuntimeModel);
        assert.exists(runtimeModel);
        const executionContext = runtimeModel.executionContext(id);
        assert.exists(executionContext);
        return executionContext;
    }
    function dispatchKeydown(key, options = {}) {
        editor.editor.contentDOM.dispatchEvent(new KeyboardEvent('keydown', {
            key,
            bubbles: true,
            ...options,
        }));
    }
    function setCodeMirrorContent(content, { selectionHead } = { selectionHead: content.length }) {
        editor.dispatch({
            changes: { from: 0, to: editor.state.doc.length, insert: content },
            selection: { anchor: selectionHead },
        });
    }
    it('evaluates on enter', async () => {
        dispatchKeydown('Enter');
        await new Promise(resolve => setTimeout(resolve, 0));
        sinon.assert.called(evaluateOnTarget);
    });
    it('allows user to enable pasting by typing \'allow pasting\'', async () => {
        const setting = Common.Settings.Settings.instance().createSetting('disable-self-xss-warning', false, "Synced" /* Common.Settings.SettingStorageType.SYNCED */);
        assert.isFalse(setting.get());
        consolePrompt.showSelfXssWarning();
        dispatchKeydown('Enter');
        await new Promise(resolve => setTimeout(resolve, 0));
        assert.isFalse(setting.get());
        consolePrompt.showSelfXssWarning();
        setCodeMirrorContent('allow pasting');
        dispatchKeydown('Enter');
        await new Promise(resolve => setTimeout(resolve, 0));
        assert.isTrue(setting.get());
    });
    it('does not evaluate incomplete expression', async () => {
        compileScript.resolves(compileScriptResponse('SyntaxError: Unexpected end of input'));
        dispatchKeydown('Enter');
        await new Promise(resolve => setTimeout(resolve, 0));
        sinon.assert.notCalled(evaluateOnTarget);
    });
    it('evaluate incomplete expression if forced', async () => {
        compileScript.resolves(compileScriptResponse('SyntaxError: Unexpected end of input'));
        dispatchKeydown('Ctrl-Enter');
        await new Promise(resolve => setTimeout(resolve, 0));
        sinon.assert.called(evaluateOnTarget);
    });
    it('does not evaluate if the current context has changed', async () => {
        const anotherTarget = createTarget();
        const anotherTargetContext = createExecutionContext(target);
        const evaluateOnAnotherTarget = sinon.stub(anotherTarget.runtimeAgent(), 'invoke_evaluate');
        sinon.stub(anotherTarget.runtimeAgent(), 'invoke_compileScript').resolves(compileScriptResponse());
        dispatchKeydown('Enter');
        UI.Context.Context.instance().setFlavor(SDK.RuntimeModel.ExecutionContext, anotherTargetContext);
        await new Promise(resolve => setTimeout(resolve, 0));
        sinon.assert.notCalled(evaluateOnAnotherTarget);
        sinon.assert.notCalled(evaluateOnTarget);
    });
    it('handles event sequence correctly', async () => {
        const stub = sinon.stub(TextEditor.TextEditorHistory.TextEditorHistory.prototype, 'moveHistory');
        // Verify that ArrowUp with repeat does not move history.
        dispatchKeydown('ArrowUp', { repeat: true });
        await new Promise(resolve => setTimeout(resolve, 0));
        sinon.assert.notCalled(stub);
        // Verify that ArrowUp does move history.
        dispatchKeydown('ArrowUp');
        await new Promise(resolve => setTimeout(resolve, 0));
        sinon.assert.calledOnceWithExactly(stub, -1 /* TextEditor.TextEditorHistory.Direction.BACKWARD */);
        stub.resetHistory();
        // Verify that ArrowDown with repeat does not move history.
        dispatchKeydown('ArrowDown', { repeat: true });
        await new Promise(resolve => setTimeout(resolve, 0));
        sinon.assert.notCalled(stub);
        // Verify that ArrowDown does move history.
        dispatchKeydown('ArrowDown');
        await new Promise(resolve => setTimeout(resolve, 0));
        sinon.assert.calledOnceWithExactly(stub, 1 /* TextEditor.TextEditorHistory.Direction.FORWARD */);
    });
});
//# sourceMappingURL=ConsolePrompt.test.js.map