// Copyright (c) 2026, Compiler Explorer Authors
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

import {serialiseState} from '../../shared/url-serialization.js';
import {
    assertNoConsoleOutput,
    monacoEditorTextShouldContain,
    setMonacoEditorContent,
    stubConsoleOutput,
} from '../support/utils';

// A minimal editor + compiler layout, like the ones generated by "Share > Embed in iframe".
function buildEmbeddedState(source: string) {
    return {
        version: 4,
        content: [
            {
                type: 'row',
                content: [
                    {
                        type: 'component',
                        componentName: 'codeEditor',
                        componentState: {id: 1, lang: 'c++', source},
                        isClosable: true,
                    },
                    {
                        type: 'component',
                        componentName: 'compiler',
                        componentState: {compiler: 'gdefault', id: 1, lang: 'c++', source: 1},
                        isClosable: true,
                    },
                ],
            },
        ],
    };
}

const EMBEDDED_SOURCE = 'int embedded_marker(int num) {\n    return num * 3;\n}';

// Embedded panes have no tab headers (hasHeaders: false), so we can't use the
// lm_title-based helpers; the source editor is the first Monaco editor created.
function embeddedSourceEditor() {
    return cy.get('.monaco-editor').first();
}

describe('Embedded mode', () => {
    let stateHash: string;

    beforeEach(() => {
        stateHash = serialiseState(buildEmbeddedState(EMBEDDED_SOURCE));
        cy.visit(`/e#${stateHash}`, {
            onBeforeLoad: win => {
                stubConsoleOutput(win);
            },
        });
    });

    afterEach(() => {
        return cy.window().then(_win => {
            assertNoConsoleOutput();
        });
    });

    it('loads the embedded code rather than the default example', () => {
        monacoEditorTextShouldContain(embeddedSourceEditor(), 'embedded_marker');
    });

    it('keeps the /e path and state hash in the URL across state changes', () => {
        // Regression test for #8896: ensureUrlIsNotOutdated() used to rewrite the
        // iframe URL to httpRoot ("/") once the layout state diverged from the
        // state recorded after load, dropping both the /e path and the #hash.
        // Browsers that restore an iframe's session-history URL when the parent
        // page reloads (Firefox) then loaded the full site instead of the embed:
        // default example code plus, cross-site cookies being unreadable, the
        // privacy policy popup.
        monacoEditorTextShouldContain(embeddedSourceEditor(), 'embedded_marker');

        // Edit the source twice, each time waiting for the "Edit on Compiler
        // Explorer" link to pick up the new state. The link is updated by the
        // same stateChanged handler that (before the fix) rewrote the URL, so
        // once the second distinct state has been observed in the link, the
        // buggy rewrite would definitely have happened.
        setMonacoEditorContent('int changed_marker(int num) {\n    return num * 4;\n}');
        cy.get('a.link').should('have.attr', 'href').and('include', 'changed_marker');

        setMonacoEditorContent('int changed_again(int num) {\n    return num * 5;\n}');
        cy.get('a.link').should('have.attr', 'href').and('include', 'changed_again');

        cy.location('pathname').should('equal', '/e');
        cy.location('hash').should('equal', `#${stateHash}`);
    });
});
