// 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 { createConsoleInsightWidget } from '../../../testing/ConsoleInsightHelpers.js';
import { assertScreenshot, renderElementIntoDOM, } from '../../../testing/DOMHelpers.js';
import { describeWithEnvironment, updateHostConfig } from '../../../testing/EnvironmentHelpers.js';
import * as MarkdownView from '../../../ui/components/markdown_view/markdown_view.js';
import * as Lit from '../../../ui/lit/lit.js';
import * as Console from '../../console/console.js';
import * as Explain from '../explain.js';
describeWithEnvironment('ConsoleInsight', () => {
    let component;
    const containerCss = `
      box-sizing: border-box;
      background-color: aqua;
    `;
    beforeEach(() => {
        sinon.stub(Host.AidaClient.HostConfigTracker.instance(), 'pollAidaAvailability').callsFake(async () => { });
    });
    afterEach(() => {
        component?.detach();
        Common.Settings.settingForTest('console-insights-enabled').set(true);
        Common.Settings.settingForTest('console-insights-onboarding-finished').set(true);
    });
    it('shows opt-in teaser when setting is turned off', async () => {
        Common.Settings.settingForTest('console-insights-enabled').set(false);
        const { view, component } = await createConsoleInsightWidget();
        assert.strictEqual(view.input.state.type, "loading" /* Explain.State.LOADING */);
        component.wasShown();
        const nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "setting-is-not-true" /* Explain.State.SETTING_IS_NOT_TRUE */);
    });
    it('shows opt-in teaser when blocked by age', async () => {
        updateHostConfig({
            aidaAvailability: {
                blockedByAge: true,
            },
            devToolsConsoleInsights: {
                enabled: true,
            },
        });
        const { view, component } = await createConsoleInsightWidget();
        assert.strictEqual(view.input.state.type, "loading" /* Explain.State.LOADING */);
        component.wasShown();
        const nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "setting-is-not-true" /* Explain.State.SETTING_IS_NOT_TRUE */);
    });
    it('generates an explanation when the user logs in', async () => {
        const { view, component, stubAidaCheckAccessPreconditions } = await createConsoleInsightWidget({
            aidaAvailability: "no-account-email" /* Host.AidaClient.AidaAccessPreconditions.NO_ACCOUNT_EMAIL */,
        });
        assert.strictEqual(view.input.state.type, "not-logged-in" /* Explain.State.NOT_LOGGED_IN */);
        component.wasShown();
        stubAidaCheckAccessPreconditions("available" /* Host.AidaClient.AidaAccessPreconditions.AVAILABLE */);
        Host.AidaClient.HostConfigTracker.instance().dispatchEventToListeners("aidaAvailabilityChanged" /* Host.AidaClient.Events.AIDA_AVAILABILITY_CHANGED */);
        const nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "insight" /* Explain.State.INSIGHT */);
    });
    it('shows opt-in teaser when setting is disabled via disabledCondition', async () => {
        const setting = Common.Settings.settingForTest('console-insights-enabled');
        setting.setRegistration({
            settingName: 'console-insights-enabled',
            settingType: "boolean" /* Common.Settings.SettingType.BOOLEAN */,
            defaultValue: true,
            disabledCondition: () => {
                return { disabled: true, reasons: ['disabled for test'] };
            },
        });
        const { view, component } = await createConsoleInsightWidget();
        assert.strictEqual(view.input.state.type, "loading" /* Explain.State.LOADING */);
        component.wasShown();
        const nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "setting-is-not-true" /* Explain.State.SETTING_IS_NOT_TRUE */);
        setting.setRegistration({
            settingName: 'console-insights-enabled',
            settingType: "boolean" /* Common.Settings.SettingType.BOOLEAN */,
            defaultValue: false,
        });
    });
    it('shows reminder on first run of console insights', async () => {
        Common.Settings.settingForTest('console-insights-onboarding-finished').set(false);
        const { view, component } = await createConsoleInsightWidget();
        assert.strictEqual(view.input.state.type, "loading" /* Explain.State.LOADING */);
        component.wasShown();
        let nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "consent-reminder" /* Explain.State.CONSENT_REMINDER */);
        await view.input.callbacks.onConsentReminderConfirmed();
        nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "insight" /* Explain.State.INSIGHT */);
    });
    it('shows an error message on timeout', async () => {
        function getAidaClientWithTimeout() {
            return {
                async *doConversation() {
                    yield {
                        explanation: 'test',
                        metadata: {
                            rpcGlobalId: 0,
                        },
                        completed: true,
                    };
                    throw new Error('doAidaConversation timed out');
                },
                registerClientEvent: sinon.spy(),
            };
        }
        const { view, component } = await createConsoleInsightWidget({
            aidaClient: getAidaClientWithTimeout(),
        });
        assert.strictEqual(view.input.state.type, "loading" /* Explain.State.LOADING */);
        component.wasShown();
        const nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "insight" /* Explain.State.INSIGHT */);
        const insight = nextInput.state;
        assert.isTrue(insight.timedOut);
    });
    const reportsRating = (positive, disallowLogging) => async () => {
        updateHostConfig({
            aidaAvailability: {
                disallowLogging,
            },
        });
        const actionTaken = sinon.stub(Host.userMetrics, 'actionTaken');
        const { view, component, testAidaClient } = await createConsoleInsightWidget();
        component.wasShown();
        await view.nextInput;
        await view.input.callbacks.onRating(positive);
        await view.nextInput;
        sinon.assert.calledOnce(testAidaClient.registerClientEvent);
        sinon.assert.match(testAidaClient.registerClientEvent.firstCall.firstArg, sinon.match({
            corresponding_aida_rpc_global_id: 0,
            disable_user_content_logging: disallowLogging,
            do_conversation_client_event: {
                user_feedback: { sentiment: positive ? 'POSITIVE' : 'NEGATIVE' },
            },
        }));
        sinon.assert.calledWith(actionTaken, positive ? Host.UserMetrics.Action.InsightRatedPositive : Host.UserMetrics.Action.InsightRatedNegative);
        await view.input.callbacks.onRating(positive);
        sinon.assert.calledOnce(testAidaClient.registerClientEvent);
    };
    it('report if the user is not logged in', async () => {
        const { view } = await createConsoleInsightWidget({
            aidaAvailability: "no-account-email" /* Host.AidaClient.AidaAccessPreconditions.NO_ACCOUNT_EMAIL */,
        });
        assert.strictEqual(view.input.state.type, "not-logged-in" /* Explain.State.NOT_LOGGED_IN */);
    });
    it('report if the navigator is offline', async () => {
        const { view } = await createConsoleInsightWidget({
            aidaAvailability: "no-internet" /* Host.AidaClient.AidaAccessPreconditions.NO_INTERNET */,
        });
        assert.strictEqual(view.input.state.type, "offline" /* Explain.State.OFFLINE */);
    });
    it('displays factuality metadata as related content', async () => {
        function getAidaClientWithMetadata() {
            return {
                async *doConversation() {
                    yield {
                        explanation: 'test',
                        metadata: {
                            rpcGlobalId: 0,
                            factualityMetadata: {
                                facts: [
                                    { sourceUri: 'https://www.firstSource.test/someInfo' },
                                    { sourceUri: 'https://www.anotherSource.test/page' },
                                ],
                            },
                        },
                        completed: true,
                    };
                },
                registerClientEvent: sinon.spy(),
            };
        }
        const { view, component } = await createConsoleInsightWidget({
            aidaClient: getAidaClientWithMetadata(),
        });
        component.wasShown();
        const nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "insight" /* Explain.State.INSIGHT */);
        const insight = nextInput.state;
        assert.deepEqual(insight.relatedUrls, [
            'https://www.firstSource.test/someInfo',
            'https://www.anotherSource.test/page',
        ]);
    });
    it('displays direct citations', async () => {
        function getAidaClientWithMetadata() {
            return {
                async *doConversation() {
                    yield {
                        explanation: 'This is not a real answer, it is just a test.',
                        metadata: {
                            rpcGlobalId: 0,
                            attributionMetadata: {
                                attributionAction: Host.AidaClient.RecitationAction.CITE,
                                citations: [
                                    {
                                        startIndex: 0,
                                        endIndex: 10,
                                        uri: 'https://www.wiki.test/directSource',
                                        sourceType: Host.AidaClient.CitationSourceType.WORLD_FACTS,
                                    },
                                    {
                                        startIndex: 20,
                                        endIndex: 25,
                                        uri: 'https://www.world-fact.test/',
                                        sourceType: Host.AidaClient.CitationSourceType.WORLD_FACTS,
                                    },
                                ],
                            },
                            factualityMetadata: {
                                facts: [
                                    { sourceUri: 'https://www.firstSource.test/someInfo' },
                                ],
                            },
                        },
                        completed: true,
                    };
                },
                registerClientEvent: sinon.spy(),
            };
        }
        const { view, component } = await createConsoleInsightWidget({
            aidaClient: getAidaClientWithMetadata(),
        });
        component.wasShown();
        let nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "insight" /* Explain.State.INSIGHT */);
        const insight = nextInput.state;
        assert.deepEqual(insight.directCitationUrls, [
            'https://www.wiki.test/directSource',
            'https://www.world-fact.test/',
        ]);
        assert.deepEqual(insight.relatedUrls, [
            'https://www.firstSource.test/someInfo',
        ]);
        view.input.citationClickHandler(1);
        nextInput = await view.nextInput;
        assert.isTrue(nextInput.areReferenceDetailsOpen);
        assert.strictEqual(nextInput.highlightedCitationIndex, 0);
    });
    it('displays direct citations in code blocks', async () => {
        function getAidaClientWithMetadata() {
            return {
                async *doConversation() {
                    yield {
                        explanation: `before

\`\`\`\`\`
const foo = document.querySelector('.some-class');
\`\`\`\`\`

after
`,
                        metadata: {
                            rpcGlobalId: 0,
                            attributionMetadata: {
                                attributionAction: Host.AidaClient.RecitationAction.CITE,
                                citations: [
                                    {
                                        startIndex: 20,
                                        endIndex: 25,
                                        uri: 'https://www.wiki.test/directSource',
                                        sourceType: Host.AidaClient.CitationSourceType.WORLD_FACTS,
                                    },
                                    {
                                        startIndex: 30,
                                        endIndex: 38,
                                        uri: 'https://www.world-fact.test/',
                                        sourceType: Host.AidaClient.CitationSourceType.WORLD_FACTS,
                                    },
                                ],
                            },
                            factualityMetadata: {
                                facts: [
                                    { sourceUri: 'https://www.firstSource.test/someInfo' },
                                ],
                            },
                        },
                        completed: true,
                    };
                },
                registerClientEvent: sinon.spy(),
            };
        }
        const { view, component } = await createConsoleInsightWidget({
            aidaClient: getAidaClientWithMetadata(),
        });
        component.wasShown();
        let nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "insight" /* Explain.State.INSIGHT */);
        const insight = nextInput.state;
        assert.lengthOf(insight.directCitationUrls, 2);
        assert.strictEqual(insight.directCitationUrls[0], 'https://www.wiki.test/directSource');
        assert.strictEqual(insight.directCitationUrls[1], 'https://www.world-fact.test/');
        assert.isFalse(nextInput.areReferenceDetailsOpen);
        assert.strictEqual(nextInput.highlightedCitationIndex, -1);
        nextInput.citationClickHandler(1);
        nextInput = await view.nextInput;
        assert.isTrue(nextInput.areReferenceDetailsOpen);
        assert.strictEqual(nextInput.highlightedCitationIndex, 0);
    });
    it('displays training data citations', async () => {
        function getAidaClientWithMetadata() {
            return {
                async *doConversation() {
                    yield {
                        explanation: 'This is not a real answer, it is just a test.',
                        metadata: {
                            rpcGlobalId: 0,
                            attributionMetadata: {
                                attributionAction: Host.AidaClient.RecitationAction.CITE,
                                citations: [
                                    {
                                        startIndex: 5,
                                        endIndex: 9,
                                        uri: 'https://www.training.test/',
                                        sourceType: Host.AidaClient.CitationSourceType.TRAINING_DATA,
                                    },
                                    {
                                        startIndex: 15,
                                        endIndex: 22,
                                        repository: 'chromedevtools/devtools-frontend',
                                        sourceType: Host.AidaClient.CitationSourceType.TRAINING_DATA,
                                    },
                                ],
                            },
                            factualityMetadata: {
                                facts: [
                                    { sourceUri: 'https://www.firstSource.test/someInfo' },
                                ],
                            },
                        },
                        completed: true,
                    };
                },
                registerClientEvent: sinon.spy(),
            };
        }
        const { view, component } = await createConsoleInsightWidget({
            aidaClient: getAidaClientWithMetadata(),
        });
        component.wasShown();
        const nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "insight" /* Explain.State.INSIGHT */);
        const insight = nextInput.state;
        assert.lengthOf(insight.relatedUrls, 3);
        assert.strictEqual(insight.relatedUrls[0], 'https://www.firstSource.test/someInfo');
        assert.strictEqual(insight.relatedUrls[1], 'https://www.training.test/');
        assert.strictEqual(insight.relatedUrls[2], 'https://www.github.com/chromedevtools/devtools-frontend');
    });
    it('deduplicates citation URLs', async () => {
        function getAidaClientWithMetadata() {
            return {
                async *doConversation() {
                    yield {
                        explanation: 'This is not a real answer, it is just a test.',
                        metadata: {
                            rpcGlobalId: 0,
                            attributionMetadata: {
                                attributionAction: Host.AidaClient.RecitationAction.CITE,
                                citations: [
                                    {
                                        startIndex: 5,
                                        endIndex: 9,
                                        uri: 'https://www.training-and-factuality.test/',
                                        sourceType: Host.AidaClient.CitationSourceType.TRAINING_DATA,
                                    },
                                    {
                                        startIndex: 10,
                                        endIndex: 12,
                                        uri: 'https://www.all-three.test/',
                                        sourceType: Host.AidaClient.CitationSourceType.TRAINING_DATA,
                                    },
                                    {
                                        startIndex: 20,
                                        endIndex: 25,
                                        uri: 'https://www.world-fact-and-factuality.test/',
                                        sourceType: Host.AidaClient.CitationSourceType.WORLD_FACTS,
                                    },
                                    {
                                        startIndex: 26,
                                        endIndex: 30,
                                        uri: 'https://www.all-three.test/',
                                        sourceType: Host.AidaClient.CitationSourceType.WORLD_FACTS,
                                    },
                                ],
                            },
                            factualityMetadata: {
                                facts: [
                                    { sourceUri: 'https://www.training-and-factuality.test/' },
                                    { sourceUri: 'https://www.world-fact-and-factuality.test/' },
                                    { sourceUri: 'https://www.factuality.test/' },
                                    { sourceUri: 'https://www.all-three.test/' },
                                ],
                            },
                        },
                        completed: true,
                    };
                },
                registerClientEvent: sinon.spy(),
            };
        }
        const { view, component } = await createConsoleInsightWidget({
            aidaClient: getAidaClientWithMetadata(),
        });
        component.wasShown();
        const nextInput = await view.nextInput;
        assert.strictEqual(nextInput.state.type, "insight" /* Explain.State.INSIGHT */);
        const insight = nextInput.state;
        assert.lengthOf(insight.directCitationUrls, 2);
        assert.lengthOf(insight.relatedUrls, 2);
        assert.strictEqual(insight.directCitationUrls[0], 'https://www.world-fact-and-factuality.test/');
        assert.strictEqual(insight.directCitationUrls[1], 'https://www.all-three.test/');
        assert.strictEqual(insight.relatedUrls[0], 'https://www.training-and-factuality.test/');
        assert.strictEqual(insight.relatedUrls[1], 'https://www.factuality.test/');
    });
    const DEFAULT_INPUT = {
        state: { type: "loading" /* Explain.State.LOADING */ },
        closing: false,
        disableAnimations: true,
        renderer: new MarkdownView.MarkdownView.MarkdownInsightRenderer(),
        citationClickHandler: () => { },
        noLogging: false,
        areReferenceDetailsOpen: false,
        highlightedCitationIndex: -1,
        callbacks: {
            onClose: () => { },
            onAnimationEnd: () => { },
            onCitationAnimationEnd: () => { },
            onSearch: () => { },
            onRating: (_isPositive) => undefined,
            onReport: () => { },
            onGoToSignIn: () => { },
            onConsentReminderConfirmed: async () => { },
            onToggleReferenceDetails: (_event) => { },
            onDisclaimerSettingsLink: () => { },
            onReminderSettingsLink: () => { },
            onEnableInsightsInSettingsLink: () => { },
            onReferencesOpen: () => { },
        }
    };
    const createViewOutput = () => ({
        headerRef: Lit.Directives.createRef(),
        citationLinks: [],
    });
    function createTarget(width, height) {
        const container = document.createElement('div');
        container.style.cssText = containerCss;
        const target = document.createElement('div');
        target.style.width = width;
        target.style.height = height;
        container.appendChild(target);
        renderElementIntoDOM(container);
        return target;
    }
    it('renders the opt-in teaser', async () => {
        const target = createTarget('574px', '64px');
        Explain.DEFAULT_VIEW({
            ...DEFAULT_INPUT,
            state: { type: "setting-is-not-true" /* Explain.State.SETTING_IS_NOT_TRUE */ },
        }, createViewOutput(), target);
        await assertScreenshot('explain/console_insight_optin.png');
    });
    it('renders the consent reminder', async () => {
        const target = createTarget('574px', '271px');
        Explain.DEFAULT_VIEW({
            ...DEFAULT_INPUT,
            state: { type: "consent-reminder" /* Explain.State.CONSENT_REMINDER */ },
        }, createViewOutput(), target);
        await assertScreenshot('explain/console_insight_reminder.png');
    });
    const rendersInsight = (noLogging, golden) => async () => {
        const target = createTarget('574px', '530px');
        Explain.DEFAULT_VIEW({
            ...DEFAULT_INPUT,
            noLogging,
            state: {
                type: "insight" /* Explain.State.INSIGHT */,
                tokens: [
                    {
                        type: 'heading',
                        raw: '## Result\n\n',
                        depth: 2,
                        text: 'Result',
                        tokens: [{ type: 'text', raw: 'Result', text: 'Result' }]
                    },
                    {
                        type: 'paragraph',
                        raw: 'Some text with `code`. Some code:\n',
                        text: 'Some text with `code`. Some code:',
                        tokens: [
                            { type: 'text', raw: 'Some text with ', text: 'Some text with ' },
                            { type: 'codespan', raw: '`code`', text: 'code' },
                            { type: 'text', raw: '. Some code:', text: '. Some code:' }
                        ]
                    },
                    {
                        type: 'code',
                        raw: '```ts\nconsole.log(\'test\');\ndocument.querySelector(\'test\').style = \'black\';\n```',
                        lang: 'ts',
                        text: 'console.log(\'test\');\ndocument.querySelector(\'test\').style = \'black\';'
                    },
                    { type: 'space', raw: '\n\n' }, {
                        type: 'code',
                        raw: '```\n<!DOCTYPE html>\n<div>Hello world</div>\n<script>\n  console.log(\'Hello World\');\n</script>\n```',
                        lang: '',
                        text: '<!DOCTYPE html>\n<div>Hello world</div>\n<script>\n  console.log(\'Hello World\');\n</script>'
                    },
                    { type: 'space', raw: '\n\n' }, {
                        type: 'paragraph',
                        raw: 'Links: [https://example.com](https://example.com)\nImages: ![https://example.com](https://example.com)\n',
                        text: 'Links: [https://example.com](https://example.com)\nImages: ![https://example.com](https://example.com)',
                        tokens: [
                            { type: 'text', raw: 'Links: ', text: 'Links: ' }, {
                                type: 'link',
                                raw: '[https://example.com](https://example.com)',
                                href: 'https://example.com',
                                title: null,
                                text: 'https://example.com',
                                tokens: [{ type: 'text', raw: 'https://example.com', text: 'https://example.com' }]
                            },
                            { type: 'text', raw: '\nImages: ', text: '\nImages: ' }, {
                                type: 'image',
                                raw: '![https://example.com](https://example.com)',
                                href: 'https://example.com',
                                title: null,
                                text: 'https://example.com'
                            }
                        ]
                    }
                ],
                validMarkdown: true,
                explanation: '## Result\n\nSome text with `code`. Some code:\n```ts\nconsole.log(\'test\');\ndocument.querySelector(\'test\').style = \'black\';\n```\n\n```\n<!DOCTYPE html>\n<div>Hello world</div>\n<script>\n  console.log(\'Hello World\');\n</script>\n```\n\nLinks: [https://example.com](https://example.com)\nImages: ![https://example.com](https://example.com)\n',
                sources: [
                    {
                        type: Console.PromptBuilder.SourceType.MESSAGE,
                        value: 'Something went wrong\n\nSomething went wrong'
                    },
                    { type: Console.PromptBuilder.SourceType.STACKTRACE, value: 'Stacktrace line1\nStacketrace line2' },
                    { type: Console.PromptBuilder.SourceType.RELATED_CODE, value: 'RelatedCode' }, {
                        type: Console.PromptBuilder.SourceType.NETWORK_REQUEST,
                        value: 'Request: https://example.com/data.html\n\nRequest headers:\n:authority: example.com\nuser-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36\n\nResponse headers:\nResponse status: 404'
                    }
                ],
                metadata: {},
                isPageReloadRecommended: false,
                completed: true,
                directCitationUrls: [],
                relatedUrls: []
            }
        }, createViewOutput(), target);
        await assertScreenshot(golden);
    };
    describe('without logging', () => {
        it('reports positive rating', reportsRating(true, true));
        it('reports negative rating', reportsRating(false, true));
        // formerly 'has thumbs up/down buttons if logging is disabled'
        it('renders the insight', rendersInsight(true, 'explain/console_insight_no_logging.png'));
    });
    describe('with logging', () => {
        it('reports positive rating', reportsRating(true, false));
        it('reports negative rating', reportsRating(false, false));
        it('renders the insight', rendersInsight(false, 'explain/console_insight.png'));
    });
    it('renders insights with references', async () => {
        const target = createTarget('576px', '463px');
        Explain.DEFAULT_VIEW({
            ...DEFAULT_INPUT,
            areReferenceDetailsOpen: true,
            state: {
                type: "insight" /* Explain.State.INSIGHT */,
                tokens: [
                    {
                        type: 'heading',
                        raw: '## Result\n\n',
                        depth: 2,
                        text: 'Result',
                        tokens: [{ type: 'text', raw: 'Result', text: 'Result' }]
                    },
                    {
                        type: 'paragraph',
                        raw: 'Here is a text which contains both direct[^1] and indirect citations.',
                        text: 'Here is a text which contains both direct[^1] and indirect citations.',
                        tokens: [
                            {
                                type: 'text',
                                raw: 'Here is a text which contains both direct',
                                text: 'Here is a text which contains both direct'
                            },
                            { type: 'citation', raw: '[^1]', linkText: 1 },
                            { type: 'text', raw: ' and indirect citations.', text: ' and indirect citations.' }
                        ]
                    },
                    { type: 'space', raw: '\n\n' }, {
                        type: 'paragraph',
                        raw: 'An indirect citation is a link to a reference which applies to the whole response.',
                        text: 'An indirect citation is a link to a reference which applies to the whole response.',
                        tokens: [{
                                type: 'text',
                                raw: 'An indirect citation is a link to a reference which applies to the whole response.',
                                text: 'An indirect citation is a link to a reference which applies to the whole response.'
                            }]
                    },
                    { type: 'space', raw: '\n\n' }, {
                        type: 'paragraph',
                        raw: 'A direct citation[^2] is a link to a reference, but it only applies to a specific part of the response. Direct citations are numbered and are shown as a number within square brackets in the response text.\n',
                        text: 'A direct citation[^2] is a link to a reference, but it only applies to a specific part of the response. Direct citations are numbered and are shown as a number within square brackets in the response text.',
                        tokens: [
                            { type: 'text', raw: 'A direct citation', text: 'A direct citation' },
                            { type: 'citation', raw: '[^2]', linkText: 2 }, {
                                type: 'text',
                                raw: ' is a link to a reference, but it only applies to a specific part of the response. Direct citations are numbered and are shown as a number within square brackets in the response text.',
                                text: ' is a link to a reference, but it only applies to a specific part of the response. Direct citations are numbered and are shown as a number within square brackets in the response text.'
                            }
                        ]
                    }
                ],
                validMarkdown: true,
                explanation: '## Result\n\nHere is a text which contains both direct and indirect citations.\n\nAn indirect citation is a link to a reference which applies to the whole response.\n\nA direct citation is a link to a reference, but it only applies to a specific part of the response. Direct citations are numbered and are shown as a number within square brackets in the response text.\n',
                sources: [
                    { type: Console.PromptBuilder.SourceType.MESSAGE, value: 'Something went wrong\n\nSomething went wrong' },
                    { type: Console.PromptBuilder.SourceType.STACKTRACE, value: 'Stacktrace line1\nStacketrace line2' },
                    { type: Console.PromptBuilder.SourceType.RELATED_CODE, value: 'RelatedCode' }, {
                        type: Console.PromptBuilder.SourceType.NETWORK_REQUEST,
                        value: 'Request: https://example.com/data.html\n\nRequest headers:\n:authority: example.com\nuser-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36\n\nResponse headers:\nResponse status: 404'
                    }
                ],
                metadata: {
                    attributionMetadata: {
                        attributionAction: Host.AidaClient.RecitationAction.CITE,
                        citations: [
                            {
                                startIndex: 20,
                                endIndex: 50,
                                uri: 'https://www.direct-citation.dev',
                                sourceType: Host.AidaClient.CitationSourceType.WORLD_FACTS,
                            },
                            {
                                startIndex: 170,
                                endIndex: 176,
                                uri: 'https://www.another-direct-citation.dev',
                                sourceType: Host.AidaClient.CitationSourceType.WORLD_FACTS,
                            }
                        ]
                    },
                    factualityMetadata: {
                        facts: [
                            { sourceUri: 'https://www.indirect-citation.dev' }, { sourceUri: 'https://www.the-whole-world.dev' },
                            { sourceUri: 'https://www.even-more-content.dev' }
                        ]
                    }
                },
                isPageReloadRecommended: false,
                completed: true,
                directCitationUrls: ['https://www.direct-citation.dev', 'https://www.another-direct-citation.dev'],
                relatedUrls: [
                    'https://www.indirect-citation.dev', 'https://www.the-whole-world.dev',
                    'https://www.even-more-content.dev'
                ]
            }
        }, createViewOutput(), target);
        await assertScreenshot('explain/console_insight_references.png');
    });
});
//# sourceMappingURL=ConsoleInsight.test.js.map