// 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 SDK from '../../core/sdk/sdk.js';
import { createTarget, describeWithEnvironment, registerNoopActions, stubNoopSettings, } from '../../testing/EnvironmentHelpers.js';
import { MockCDPConnection } from '../../testing/MockCDPConnection.js';
import { setMockResourceTree, } from '../../testing/ResourceTreeHelpers.js';
import * as UI from '../../ui/legacy/legacy.js';
import * as Elements from './elements.js';
const NODE_ID = 1;
describeWithEnvironment('InspectElementModeController', () => {
    let inScopeTarget;
    let inScopeSubTarget;
    let outOfScopeTarget;
    let outOfScopeSubTarget;
    let modeController;
    let tabTarget;
    let connection;
    function onModeToggle(target) {
        const model = target.model(SDK.OverlayModel.OverlayModel);
        return model.once("InspectModeWillBeToggled" /* SDK.OverlayModel.Events.INSPECT_MODE_WILL_BE_TOGGLED */);
    }
    function failOnModeToggle(target) {
        const model = target.model(SDK.OverlayModel.OverlayModel);
        model.addEventListener("InspectModeWillBeToggled" /* SDK.OverlayModel.Events.INSPECT_MODE_WILL_BE_TOGGLED */, () => assert.fail('Unexpected mode toggle on out of scope target'));
    }
    beforeEach(() => {
        setMockResourceTree(false);
        stubNoopSettings();
        registerNoopActions(['elements.toggle-element-search']);
        connection = new MockCDPConnection();
        tabTarget = createTarget({ type: SDK.Target.Type.TAB, connection });
        inScopeTarget = createTarget({ parentTarget: tabTarget });
        inScopeSubTarget = createTarget({ parentTarget: inScopeTarget });
        outOfScopeTarget = createTarget({ parentTarget: tabTarget });
        outOfScopeSubTarget = createTarget({ parentTarget: outOfScopeTarget });
        failOnModeToggle(outOfScopeTarget);
        failOnModeToggle(outOfScopeSubTarget);
        SDK.TargetManager.TargetManager.instance().setScopeTarget(inScopeTarget);
        modeController = new Elements.InspectElementModeController.InspectElementModeController();
        connection.setSuccessHandler('DOM.getDocument', () => ({ root: { nodeId: NODE_ID } }));
    });
    afterEach(() => {
        tabTarget?.dispose('test');
    });
    it('synchronises mode for in scope models', async () => {
        for (const target of SDK.TargetManager.TargetManager.instance().targets()) {
            assert.isFalse(Boolean(target.model(SDK.OverlayModel.OverlayModel)?.inspectModeEnabled()));
        }
        modeController.toggleInspectMode();
        await Promise.all([onModeToggle(inScopeTarget), onModeToggle(inScopeSubTarget)]);
        const anotherInScopeSubTarget = createTarget({ parentTarget: inScopeTarget });
        await onModeToggle(anotherInScopeSubTarget);
        const anotherOutOfScopeSubTarget = createTarget({ parentTarget: inScopeTarget });
        failOnModeToggle(anotherOutOfScopeSubTarget);
        let expectToggle = false;
        const modeToggles = Promise.all([inScopeTarget, inScopeSubTarget, anotherInScopeSubTarget].map(t => onModeToggle(t).then(() => {
            assert.isTrue(expectToggle);
        })));
        outOfScopeTarget.model(SDK.OverlayModel.OverlayModel)
            ?.dispatchEventToListeners("InspectModeExited" /* SDK.OverlayModel.Events.EXITED_INSPECT_MODE */);
        await new Promise(resolve => queueMicrotask(resolve));
        expectToggle = true;
        inScopeTarget.model(SDK.OverlayModel.OverlayModel)
            ?.dispatchEventToListeners("InspectModeExited" /* SDK.OverlayModel.Events.EXITED_INSPECT_MODE */);
        await modeToggles;
    });
});
describeWithEnvironment('InspectElementModeController panel interactions', () => {
    let elementsPanel;
    let node;
    let viewManager;
    let target;
    let connection;
    beforeEach(() => {
        stubNoopSettings();
        registerNoopActions(['elements.toggle-element-search']);
        connection = new MockCDPConnection();
        target = createTarget({ connection });
        connection.setSuccessHandler('DOM.getDocument', () => ({ root: { nodeId: NODE_ID } }));
        connection.setSuccessHandler('DOM.pushNodeByPathToFrontend', () => ({ nodeId: NODE_ID }));
        viewManager = sinon.createStubInstance(UI.ViewManager.ViewManager, {
            showView: Promise.resolve(),
        });
        sinon.stub(UI.ViewManager.ViewManager, 'instance').returns(viewManager);
        Elements.InspectElementModeController.InspectElementModeController.instance({ forceNew: true });
        elementsPanel =
            sinon.createStubInstance(Elements.ElementsPanel.ElementsPanel, { revealAndSelectNode: Promise.resolve() });
        sinon.stub(Elements.ElementsPanel.ElementsPanel, 'instance').returns(elementsPanel);
        node = sinon.createStubInstance(SDK.DOMModel.DOMNode);
    });
    afterEach(() => {
        UI.Context.Context.instance().setFlavor(Common.ReturnToPanel.ReturnToPanelFlavor, null);
        target?.dispose('test');
    });
    it('node is selected and element panel shown when no return to panel flavor is present', async () => {
        UI.Context.Context.instance().setFlavor(Common.ReturnToPanel.ReturnToPanelFlavor, null);
        await SDK.OverlayModel.OverlayModel.inspectNodeHandler(node);
        sinon.assert.calledOnce(elementsPanel.revealAndSelectNode);
        sinon.assert.calledWith(elementsPanel.revealAndSelectNode.firstCall, node, sinon.match({
            showPanel: true,
            focusNode: true,
            highlightInOverlay: false,
        }));
        sinon.assert.notCalled(viewManager.showView);
    });
    it('node is selected and triggering panel is shown when return to panel flavor is present', async () => {
        UI.Context.Context.instance().setFlavor(Common.ReturnToPanel.ReturnToPanelFlavor, new Common.ReturnToPanel.ReturnToPanelFlavor('freestyler'));
        await SDK.OverlayModel.OverlayModel.inspectNodeHandler(node);
        sinon.assert.calledOnce(elementsPanel.revealAndSelectNode);
        sinon.assert.calledWith(elementsPanel.revealAndSelectNode.firstCall, node, sinon.match({
            showPanel: false,
            highlightInOverlay: false,
        }));
        sinon.assert.calledOnceWithExactly(viewManager.showView, 'freestyler', false, false);
    });
    it('elements panel is shown on second inspection if no flavor is set after the first inspection', async () => {
        UI.Context.Context.instance().setFlavor(Common.ReturnToPanel.ReturnToPanelFlavor, new Common.ReturnToPanel.ReturnToPanelFlavor('freestyler'));
        await SDK.OverlayModel.OverlayModel.inspectNodeHandler(node);
        sinon.assert.calledOnce(elementsPanel.revealAndSelectNode);
        sinon.assert.calledWith(elementsPanel.revealAndSelectNode.firstCall, node, sinon.match({
            showPanel: false,
            highlightInOverlay: false,
        }));
        await SDK.OverlayModel.OverlayModel.inspectNodeHandler(node);
        sinon.assert.calledTwice(elementsPanel.revealAndSelectNode);
        sinon.assert.calledWith(elementsPanel.revealAndSelectNode.secondCall, node, sinon.match({
            showPanel: true,
            focusNode: true,
            highlightInOverlay: false,
        }));
    });
});
//# sourceMappingURL=InspectElementModeController.test.js.map