/*!
 * Matomo - free/libre analytics platform
 *
 * Screenshot integration tests.
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */

describe("PrivacyManager", function () {
    this.fixture = "Piwik\\Plugins\\PrivacyManager\\tests\\Fixtures\\MultipleSitesMultipleVisitsFixture";

    var generalParams = 'idSite=1&period=day&date=2017-01-02',
        urlBase = '?module=PrivacyManager&' + generalParams + '&action=';

    before(function () {
        testEnvironment.pluginsToLoad = ['PrivacyManager'];
        testEnvironment.save();
    });

    async function setAnonymizeStartEndDate()
    {
        // make sure tests do not fail every day
        await page.waitForSelector('input.anonymizeStartDate');
        await page.waitForSelector('input.anonymizeEndDate');
        await page.waitForTimeout(100);
        await page.evaluate(function () {
            $('input.anonymizeStartDate').val('2018-03-02').change();
        });
        await page.waitForTimeout(100);
        await page.evaluate(function () {
            $('input.anonymizeEndDate').val('2018-03-02').change();
        });
        await page.waitForTimeout(100);
    }

    async function loadActionPage(action)
    {
        await page.goto('about:blank');
        await page.goto(urlBase + action);
        await page.waitForNetworkIdle();

        if (action === 'privacySettings') {
            await setAnonymizeStartEndDate();
        }
    }

    async function selectModalButton(button)
    {
        var elem = await page.jQuery('.modal.open .modal-footer a:contains('+button+')');
        await elem.click();
        await page.waitForTimeout(500);
        await page.waitForNetworkIdle();
    }

    async function typeUserPassword()
    {
        var elem = await page.jQuery('.modal.open #currentUserPassword');
        await elem.type(superUserPassword);
        await page.waitForTimeout(100);
    }

    async function findDataSubjects()
    {
        await page.click('.findDataSubjects .btn');
        await page.waitForNetworkIdle();
        await page.waitForTimeout(250);
    }

    async function selectSite(id)
    {
        await page.click('.siteSelector a.title');
        await page.click('.siteSelector .dropdown .custom_select_ul_list a[href*="idSite=' + id + '"]');
        await page.waitForNetworkIdle();
    }

    async function anonymizePastData()
    {
        await page.click('.anonymizePastData .btn');
        await page.waitForTimeout(1000); // wait for animation
    }

    async function deleteDataSubjects()
    {
        await page.evaluate(() => $('.deleteDataSubjects input').click());
        await page.waitForTimeout(500); // wait for animation
    }

    async function selectStartsWith()
    {
        await page.click('.metricMatchBlock input');
        await page.click('.metricMatchBlock ul.select-dropdown li:nth-child(5)');
    }

    async function enterSegmentMatchValue(value) {
        await page.evaluate(theVal => {
            $('.metricValueBlock input').each(function (index) {
                $(this).val(theVal).change();
            });
        }, value);
        await page.waitForTimeout(200);
    }

    async function selectVisitColumn(title)
    {
        await page.waitForTimeout(100);
        await page.evaluate(function () {
            $('.selectedVisitColumns:last input.select-dropdown').click();
        });
        await page.waitForTimeout(100);
        await page.evaluate(title => {
            $('.selectedVisitColumns:last .dropdown-content li:contains(' + title + ')').click();
        }, title);
        await page.waitForTimeout(100);
    }

    async function selectActionColumn(title)
    {
        await page.waitForTimeout(100);
        await page.evaluate(function () {
            $('.selectedActionColumns:last input.select-dropdown').click();
        });
        await page.waitForTimeout(100);
        await page.evaluate(theTitle => {
            $('.selectedActionColumns:last .dropdown-content li:contains(' + theTitle + ')').click();
        }, title);
        await page.waitForTimeout(100);
    }

    async function capturePage(screenshotName) {
        await page.waitForNetworkIdle();
        const pageWrap = await page.$('.pageWrap,#notificationContainer,.modal.open');
        const screenshot = await pageWrap.screenshot();
        expect(screenshot).to.matchImage(screenshotName);
    }

    async function captureAnonymizeLogData(screenshotName) {
        await page.waitForNetworkIdle();
        expect(await page.screenshotSelector('.logDataAnonymizer,#notificationContainer,.modal.open,.logDataAnonymizer table')).to.matchImage(screenshotName);
    }

    async function captureModal(screenshotName) {
        await page.waitForNetworkIdle();
        const modal = await page.$('.modal.open');
        expect(await modal.screenshot()).to.matchImage(screenshotName);
    }

    async function confirmPassword() {
        await page.$('.confirm-password-modal.open', { visible: true });
        await page.waitForTimeout(300);

        await page.evaluate((superUserPassword) => {
            $('.confirm-password-modal input[name=currentUserPassword]:visible')
                .val(superUserPassword)
                .change();
        }, superUserPassword);

        await page.waitForTimeout(250);
        await (await page.jQuery('.confirm-password-modal.open .modal-close:not(.modal-no):visible')).click();
        await page.$('.confirm-password-modal.open', { hidden: true });
        await page.waitForTimeout(300);
        await page.waitForNetworkIdle();
    }

    it('should load privacy opt out page', async function() {
        await loadActionPage('usersOptOut');
        await capturePage('users_opt_out_default');
    });

    it('should load privacy asking for consent page', async function() {
        await loadActionPage('consent');
        await capturePage('consent_default');
    });

    it('should load GDPR overview page', async function() {
        testEnvironment.overrideConfig('Deletelogs', 'delete_logs_enable', '1');
        testEnvironment.overrideConfig('Deletelogs', 'delete_logs_older_than', '95');
        testEnvironment.overrideConfig('Deletereports', 'delete_reports_enable', '1');
        testEnvironment.overrideConfig('Deletereports', 'delete_reports_older_than', '131');
        testEnvironment.save();
        await loadActionPage('gdprOverview');

        await capturePage('gdpr_overview');
    });

    it('should load GDPR overview page', async function() {
        testEnvironment.overrideConfig('Deletelogs', 'delete_logs_enable', '0');
        testEnvironment.overrideConfig('Deletereports', 'delete_reports_enable', '0');
        testEnvironment.save();
        await loadActionPage('gdprOverview');

        await capturePage('gdpr_overview_no_retention');
    });

    it('should load privacy settings page', async function() {
        await loadActionPage('privacySettings');
        await page.waitForNetworkIdle();
        await capturePage('privacy_settings_default');
    });

    it('should require password when setting config id randomisation on', async function() {
        await loadActionPage('privacySettings');
        await page.waitForNetworkIdle();

        await page.waitForSelector('div.randomizeConfigIdField label');
        await page.click('div.randomizeConfigIdField label');
        await page.click('#anonymizeIPAnchor input.btn[value=Save]');

        await capturePage('config_id_randomisation_on_password_required');
    });

    it('should save config id randomisation setting after entering password', async function() {
        await confirmPassword();
        await page.waitForNetworkIdle();

        await capturePage('config_id_randomisation_on');
    });

    it('should not require password when setting config id randomisation off', async function() {
        await loadActionPage('privacySettings');
        await page.waitForNetworkIdle();

        await page.waitForSelector('div.randomizeConfigIdField label');
        await page.click('div.randomizeConfigIdField label');
        await page.click('#anonymizeIPAnchor input.btn[value=Save]');

        await capturePage('config_id_randomisation_off_password_not_required');
    });

    it('should anonymize ip and visit column', async function() {
        await loadActionPage('privacySettings');
        await page.waitForNetworkIdle();

        await page.waitForSelector('[name="anonymizeIp"] label');
        await page.click('[name="anonymizeIp"] label');
        await selectVisitColumn('config_browser_name');
        await selectVisitColumn('config_cookie');

        await captureAnonymizeLogData('anonymizelogdata_anonymizeip_and_visit_column_prefilled');
    });

    it('should show a confirmation message before executing any anonymization', async function() {
        await anonymizePastData();

        await captureModal('anonymizelogdata_anonymizeip_and_visit_column_confirmation_message');
    });

    it('should be able to cancel anonymization of past data', async function() {
        await selectModalButton('Cancel');

        await captureAnonymizeLogData('anonymizelogdata_anonymizeip_and_visit_column_cancelled');
    });

    it('should be able to confirm anonymization of past data', async function() {
        await anonymizePastData();
        await typeUserPassword();
        await selectModalButton('Confirm');
        await setAnonymizeStartEndDate();

        await captureAnonymizeLogData('anonymizelogdata_anonymizeip_and_visit_column_confirmed');
    });

    it('should prefill anonymize location and action column', async function() {
        await loadActionPage('privacySettings');
        await page.click('[name="anonymizeLocation"] label');
        await page.click('[name="anonymizeTheUserId"] label');
        await page.waitForTimeout(500);
        await selectActionColumn('time_spent_ref_action');
        await selectActionColumn('idaction_content_name');

        await captureAnonymizeLogData('anonymizelogdata_anonymizelocation_anduserid_and_action_column_prefilled');
    });

    it('should confirm anonymize location and action column', async function() {
        await anonymizePastData();
        await typeUserPassword();
        await selectModalButton('Confirm');
        await page.waitForTimeout(1000);
        await setAnonymizeStartEndDate();

        await captureAnonymizeLogData('anonymizelogdata_anonymizelocation_anduserid_and_action_column_confirmed');
    });

    it('should anonymize only one site and different date pre filled', async function() {
        await page.click('.form-group #anonymizeSite .title');
        await page.waitForTimeout(1000);
        await page.click(".form-group #anonymizeSite [title='Site 1']");
        await page.click('[name="anonymizeIp"] label');
        await page.waitForTimeout(100);
        await page.evaluate(function () {
            $('input.anonymizeStartDate').val('2017-01-01').change();
        });
        await page.waitForTimeout(100);
        await page.evaluate(function () {
           $('input.anonymizeEndDate').val('2017-02-14').change();
        });
        await page.waitForTimeout(100);

        await captureAnonymizeLogData('anonymizelogdata_one_site_and_custom_date_prefilled');
    });

    it('should anonymize only one site and different date confirmed', async function() {
        await anonymizePastData();
        await typeUserPassword();
        await selectModalButton('Confirm');
        await page.waitForTimeout(1000);
        await setAnonymizeStartEndDate();

        await captureAnonymizeLogData('anonymizelogdata_one_site_and_custom_date_confirmed');
    });

    it('should load GDPR tools page', async function() {
        await loadActionPage('gdprTools');

        await capturePage('gdpr_tools_default');
    });

    it('should show no visitor found message', async function() {
        await enterSegmentMatchValue('userfoobar');
        await findDataSubjects();
        await page.waitForSelector('.manageGdpr tr');
        await page.mouse.move(-10, -10);

        await capturePage('gdpr_tools_no_visits_found');
    });

    it('should find visits', async function() {
        await selectStartsWith();
        await enterSegmentMatchValue('10');
        await findDataSubjects();

        await capturePage('gdpr_tools_visits_found');
    });

    it('should be able to show visitor profile', async function() {
        var elem = await page.jQuery('.visitorLogTooltip:first');
        await elem.click();
        await page.mouse.move(-10, -10);
        await page.waitForNetworkIdle();

        expect(await page.screenshotSelector('.ui-dialog')).to.matchImage('gdpr_tools_visits_showprofile');
    });

    it('should be able to add IP to segment search with one click', async function() {
        await page.click('#Piwik_Popover .visitor-profile-close');
        var elem = await page.jQuery('.visitorIp:first a');
        await elem.click();
        await page.waitForNetworkIdle();

        await capturePage('gdpr_tools_enrich_segment_by_ip');
    });

    it('should be able to uncheck a visit', async function() {
        await page.click('.entityTable tbody tr:nth-child(2) .checkInclude label');
        await page.mouse.move(-10, -10);
        await capturePage('gdpr_tools_uncheck_one_visit');
    });

    it('should ask for confirmation before deleting any visit', async function() {
        await deleteDataSubjects();
        const modal = await page.waitForSelector('.modal.open', { visible: true });
        expect(await modal.screenshot()).to.matchImage('gdpr_tools_delete_visit_unconfirmed');
    });

    it('should be able to cancel deletion and not delete any data', async function() {
        await selectModalButton('No');
        await page.waitForTimeout(500);
        await capturePage('gdpr_tools_delete_visit_cancelled');
    });

    it('should verify really no data deleted', async function() {
        await loadActionPage('gdprTools');
        await page.waitForTimeout(1000);
        await selectStartsWith();
        await enterSegmentMatchValue('10');
        await findDataSubjects();
        await page.click('.entityTable tbody tr:nth-child(2) .checkInclude label');

        await capturePage('gdpr_tools_delete_visit_cancelled_verified_no_data_deleted');
    });

    it('should be able to confirm deletion and then actually delete data', async function() {
        await deleteDataSubjects();
        await selectModalButton('Yes');

        await capturePage('gdpr_tools_delete_visit_confirmed');
    });

    it('should hide GDPR tool and show message when selecting site with visitor logs or profiles disabled', async function() {
        await selectSite('3');
        await page.waitForSelector('.dataUnavailable strong');
        expect(await page.screenshotSelector('.manageGdpr')).to.matchImage('gdpr_tools_disabled_site');
    });

    it('should work to use userid segment for a site with visits log and profile enabled', async function() {
        await loadActionPage('gdprTools');
        await selectSite('1');
        await enterSegmentMatchValue('userId203');
        await findDataSubjects();
        expect(await page.screenshotSelector('.manageGdpr')).to.matchImage('gdpr_tools_userid');
    });

    it('should load compliance page when feature flag enabled', async function() {
        testEnvironment.overrideConfig('FeatureFlags', {
          PrivacyCompliance_feature: 'enabled',
        });
        testEnvironment.save();

        await page.goto('?module=CoreAdminHome&action=home&idSite=1&period=day&date=yesterday');
        await page.waitForNetworkIdle();

        await page.waitForTimeout(150);

        await (await page.jQuery('li.menuTab:contains(Privacy) > a')).click();

        await page.waitForTimeout(150);

        const complianceMenuSelector = 'li.menuTab.active li a[href*="compliance"]';

        await page.waitForSelector(complianceMenuSelector);
        await page.click(complianceMenuSelector);

        await page.waitForNetworkIdle();
        await page.waitForSelector('.compliance', { visible: true });
        await page.waitForSelector('table.dataTable.compliance', { visible: true });

        expect(await page.screenshotSelector('.compliance')).to.matchImage('compliance');
    });

    it('should not be able to navigate to compliance page with feature flag disabled', async function() {
      testEnvironment.overrideConfig('FeatureFlags', {
        PrivacyCompliance_feature: 'disabled',
      });
      testEnvironment.save();

      await page.goto('?module=CoreAdminHome&action=home&idSite=1&period=day&date=yesterday');
      await page.waitForNetworkIdle();

      await (await page.jQuery('li.menuTab:contains(Privacy) > a')).click();

      // Not in menu
      const complianceMenuItem = await page.$('li.menuTab.active li a[href*="compliance"]');
      expect(complianceMenuItem).to.be.null;

      // Not accessible directly - empty body
      await loadActionPage('compliance');
      const isBodyEmpty = await page.evaluate(() => {
        const body = document.body;
        return body && body.children.length === 0 && body.innerText.trim() === '';
      });

      expect(isBodyEmpty).to.be.true;
    });

    it('should show compliance is enforced when checkbox is selected', async function() {
      testEnvironment.overrideConfig('FeatureFlags', {
        PrivacyCompliance_feature: 'enabled',
      });
      testEnvironment.save();

      await page.goto('?module=PrivacyManager&action=compliance&idSite=1&period=day&date=yesterday');
      await page.waitForNetworkIdle();

      await page.waitForSelector('.compliance', { visible: true });
      await (await page.jQuery('#site-1-cnil_v1-enableFeature')).click();
      await page.waitForTimeout(150);
      await (await page.jQuery('.site-1-cnil_v1-save input')).click();
      await page.waitForTimeout(150);
      await confirmPassword();

      expect(await page.screenshotSelector('.compliance')).to.matchImage('compliance_enforced');
    });

    it('should load a new compliance page when site selector is changed', async function() {
      // feature flag enabled from previous test

      await page.goto('?module=PrivacyManager&action=compliance&idSite=1&period=day&date=yesterday');
      await page.waitForNetworkIdle();
      await (await page.jQuery('#complianceSite a')).click();
      await page.waitForTimeout(150);
      await (await page.jQuery('#complianceSite li:nth-child(2)')).click();
      await page.waitForNetworkIdle();

      expect(await page.screenshotSelector('.compliance')).to.matchImage('compliance_different_site');
    });

    it('should select All Websites when idSite is not provided', async function() {
      // feature flag enabled from previous test

      await page.goto('?module=PrivacyManager&action=compliance');
      await page.waitForNetworkIdle();

      const siteSelectorContent = await page.evaluate(() => {
        return $('#complianceSite a.title').text();
      });

      expect(siteSelectorContent).to.be.equal('All Websites');
    });

    it('should select All Websites when idSite equals all', async function() {
      // feature flag enabled from previous test

      await page.goto('?module=PrivacyManager&action=compliance&idSite=all');
      await page.waitForNetworkIdle();

      const siteSelectorContent = await page.evaluate(() => {
        return $('#complianceSite a.title').text();
      });

      expect(siteSelectorContent).to.be.equal('All Websites');
    });

    it('should hide the policy controls when policy is enabled via config', async function() {
      testEnvironment.overrideConfig('CnilPolicy', {
        cnil_v1_policy_enabled: '1',
      });
      testEnvironment.overrideConfig('FeatureFlags', {
        PrivacyCompliance_feature: 'enabled',
      });
      testEnvironment.save();

      await page.goto('?module=PrivacyManager&action=compliance&idSite=all');
      await page.waitForNetworkIdle();

      expect(await page.screenshotSelector('.compliance')).to.matchImage('compliance_config_enabled');
    });
  });
