/*!
 * Matomo - free/libre analytics platform
 *
 * Installation screenshot tests.
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */
var fs = require('fs'),
    path = require('../../../../tests/lib/screenshot-testing/support/path');

describe('Installation', function () {
    this.fixture = 'Piwik\\Tests\\Fixtures\\EmptySite';

    /** Timestamp when first website came online - Tue, 06 Aug 1991 00:00:00 GMT. */
    const firstWebsiteTimestamp = 681436800;
    const installationDbName = 'newdb';

    let installationStarted;
    let pageUrl;
    let pageUrlDe;

    function deleteLocalConfigFile() {
        if (fs.existsSync(testEnvironment.configFileLocal)) {
            fs.unlinkSync(testEnvironment.configFileLocal);
        }
    }

    before(function () {
        testEnvironment.testUseMockAuth = 0;
        testEnvironment.configFileLocal = path.join(PIWIK_INCLUDE_PATH, "/tmp/test.config.ini.php");
        testEnvironment.dontUseTestConfig = true;
        testEnvironment.ignoreClearAllViewDataTableParameters = 1;
        testEnvironment.tablesPrefix = 'piwik_';
        testEnvironment.save();

        deleteLocalConfigFile();
    });

    after(function () {
        delete testEnvironment.configFileLocal;
        delete testEnvironment.dontUseTestConfig;
        delete testEnvironment.tablesPrefix;
        delete testEnvironment.testUseMockAuth;
        testEnvironment.save();
    });

    it("should display an error message when trying to access a resource w/o a config.ini.php file", async function() {
        await page.goto("?module=CoreHome&action=index");

        await page.evaluate(function () {
            // ensure screenshots are reporting same config file for comparison
            // no jQuery existing on these error pages...
            document.body.innerHTML = document.body.innerHTML.replace(
                /{\/.*\/test\.config\.ini\.php}/,
                '{/home/matomo/config/test.config.ini.php}'
            );
        });

        expect(await page.screenshot({ fullPage: true })).to.matchImage('access_no_config');
    });

    it("should lock the installer when installation first accessed more than 3 days ago", async function() {
        deleteLocalConfigFile();

        // create a valid config file
        await page.goto("");

        // overwrite access timestamp
        testEnvironment.appendToLocalConfig(`
[General]
installation_first_accessed = ${firstWebsiteTimestamp}
`);

        await page.goto("");

        expect(await page.screenshot({ fullPage: true })).to.matchImage('expired');
    });

    it("should start the installation process when the index is visited w/o a config.ini.php file", async function() {
        deleteLocalConfigFile();

        await page.goto("");

        const { firstAccessed, inProgress } = testEnvironment.readInstallationInfoFromLocalConfig();

        expect(inProgress).to.be.false;
        expect(firstAccessed).to.be.greaterThan(firstWebsiteTimestamp);

        installationStarted = firstAccessed;

        expect(await page.screenshot({ fullPage: true })).to.matchImage('start');
    });

    it("should display the system check page when next is clicked on the first page", async function() {
        await page.click('.next-step .btn');
        await page.waitForNetworkIdle();

        expect(await page.screenshot({ fullPage: true })).to.matchImage('system_check');
    });

    it("should have already created a tmp/sessions/index.htm file to prevent directory listing", async function() {
        pageUrl = page.url();

        // page.load will load by default the proxy ie. http://localhost/piwik/tests/PHPUnit/proxy/
        // but we need here to check in: http://localhost/piwik/tmp/sessions/
        await page.goto("../../../tmp/sessions/index.htm");

        expect(await page.screenshot({ fullPage: true })).to.matchImage('nothing_to_see_here');
    });

    it("should display the database setup page when next is clicked on the system check page", async function() {
        await page.goto(pageUrl);

        await page.click('.next-step .btn');
        await page.waitForNetworkIdle();

        expect(await page.screenshot({ fullPage: true })).to.matchImage('db_setup');
    });

    it("should fail when the next button is clicked and no database info is entered in the form", async function() {
        await page.click('.btn');
        await page.waitForNetworkIdle();

        expect(await page.screenshot({ fullPage: true })).to.matchImage('db_setup_fail');
    });

    it("should display the tables created page when next is clicked on the db setup page w/ correct info entered in the form", async function() {
        const { username, password } = testEnvironment.readDbInfoFromConfig();

        await page.type('input[name="username"]', username);
        await page.type('input[name="password"]', password);
        await page.type('input[name="dbname"]', installationDbName);
        await page.click('.btn');
        await page.waitForNetworkIdle();

        expect(await page.screenshot({ fullPage: true })).to.matchImage('db_created');
    });

    it("should have set the installation to be 'in progress'", async function() {
        const { firstAccessed, inProgress } = testEnvironment.readInstallationInfoFromLocalConfig();

        expect(inProgress).to.be.true;
        expect(firstAccessed).to.be.equal(installationStarted);
    });

    it("should display the superuser configuration page when next is clicked on the tables created page", async function() {
        await page.click('.next-step .btn');
        await page.waitForNetworkIdle();

        expect(await page.screenshot({ fullPage: true })).to.matchImage('superuser');
    });

    it("should un-select Professional Services newsletter checkbox when language is German", async function() {
        pageUrl = await page.url();
        pageUrlDe = pageUrl + '&language=de';

        await page.goto(pageUrlDe);

        expect(await page.screenshot({ fullPage: true })).to.matchImage('superuser_de');
    });

    it("should fail when incorrect information is entered in the superuser configuration page", async function() {
        await page.goto(pageUrl);
        await page.click('.btn');
        await page.waitForNetworkIdle();

        expect(await page.screenshot({ fullPage: true })).to.matchImage('superuser_fail');
    });

    it("should display the setup a website page when next is clicked on the filled out superuser config page", async function() {
        await page.type('input[name="login"]', 'thesuperuser');
        await page.type('input[name="password"]', 'thepassword');
        await page.type('input[name="password_bis"]', 'thepassword');
        await page.type('input[name="email"]', 'hello@piwik.org');
        await page.click('.btn');
        await page.waitForNetworkIdle();

        expect(await page.screenshot({ fullPage: true })).to.matchImage('setup_website');
    });

    it("should should fail when incorrect information is entered in the setup a website page", async function() {
        await page.click('.btn');
        await page.waitForNetworkIdle();

        expect(await page.screenshot({ fullPage: true })).to.matchImage('setup_website_fail');
    });

    it("should display the javascript tracking page when correct information is entered in the setup website page and next is clicked", async function() {
        await page.type('input[name="siteName"]', 'Serenity');
        await page.evaluate(function () {
            // cannot use sendKeys since quickform does not use placeholder attribute
            $('input[name=url]').val('serenity.com');

            $('select[name=timezone]').val('Europe/Paris');
            $('select[name=ecommerce]').val('1');
        });
        await page.click('.btn');
        await page.waitForNetworkIdle();

        // manually remove port in tracking code, since ui-test.php won't be using the correct INI config file
        await page.evaluate(function () {
            $('pre').each(function () {
                var html = $(this).html();
                html = html.replace(/localhost\:[0-9]+/g, 'localhost');
                $(this).html(html);
            });
        });

        expect(await page.screenshot({ fullPage: true })).to.matchImage('js_tracking');
    });

    it("should display the congratulations page when next is clicked on the javascript tracking page", async function() {
        await page.click('.next-step .btn');
        await page.waitForNetworkIdle();

        // the installation is NOT finished at this point
        // the user needs to click the submit button once more!
        expect(await page.screenshot({ fullPage: true })).to.matchImage('congrats');
    });

    it("should clear the configuration file when restarting the installation process", async function() {
        // restart installation
        await page.goto("");
        await page.waitForSelector('#installation');

        // go to system check
        await page.click('.next-step .btn');
        await page.waitForSelector('[vue-entry="Installation.SystemCheck"]');

        // system check will delete existing configuration file
        // but should keep "first_accessed" information
        const { firstAccessed, inProgress } = testEnvironment.readInstallationInfoFromLocalConfig();

        expect(inProgress).to.be.false;
        expect(firstAccessed).to.be.equal(installationStarted);
    });

    it("should allow reusing an existing database from a previous installation", async function() {
        // go to database setup
        await page.click('.next-step .btn');
        await page.waitForNetworkIdle();

        // submit database credentials
        const { username, password } = testEnvironment.readDbInfoFromConfig();

        await page.type('input[name="username"]', username);
        await page.type('input[name="password"]', password);
        await page.type('input[name="dbname"]', installationDbName);
        await page.click('.btn');
        await page.waitForNetworkIdle();

        expect(await page.screenshot({ fullPage: true })).to.matchImage('db_existing');
    });

    it("should skip to the congrats page as installation was already completed up to that step", async function() {
        await page.click('a[href*="reuseTables"]');
        await page.waitForSelector('.installation-finished');
    });

    it("should continue to piwik after submitting on the privacy settings form in the congrats page", async function() {
        await page.click('.btn');
        await page.waitForNetworkIdle();

        // check login form is displayed
        await page.waitForSelector('.loginForm');

        // check installation is no longer in progress
        const { firstAccessed, inProgress } = testEnvironment.readInstallationInfoFromLocalConfig();

        expect(inProgress).to.be.false;
        expect(firstAccessed).to.be.null;
    });

    it("should display an error page if installation is accessed on an installed instance", async function() {
        // go back to a previous installation step
        await page.goto(pageUrl);
        await page.waitForNetworkIdle();

        // check no installation progress information was added
        const { firstAccessed, inProgress } = testEnvironment.readInstallationInfoFromLocalConfig();

        expect(inProgress).to.be.false;
        expect(firstAccessed).to.be.null;

        expect(await page.screenshot({ fullPage: true })).to.matchImage('already_installed');
    });
});
