/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict"

/**
 * Constructs a url for an intermediate "bounce" hop which represents a tracker.
 * @param {string} cacheHelper - Unique uuid for this test
 * @param {*} options - URL generation options.
 * @param {boolean} [options.second_origin = true] - whether domain should be a different origin
 * @param {boolean} [options.subdomain = false] - whether the domain should start with
 *        a different subdomain
 * @param {boolean} [options.cache = false] - whether the resource should be cacheable
 * @param {(null|'cache'|'all')} [options.clear] - whether to send the
 *        Clear-Site-Data header.
 * @param {(null|'cache'|'all')} [options.clear_first] - whether to send the
 *        Clear-Site-Data header on first response
 * @param {string} [response] - which response to elict - defaults to "single_html". Other
 *        options can be found in "clear-site-data-cache.py" server helper.
 * @param {*} [options.iframe] - iframe same parameters as options (recursive). Only works on
 *        "single_html" variation of response
 */
function getUrl(cacheHelper, {
    subdomain = false,
    secondOrigin = false,
    cache = false,
    clear = null,
    clearFirst = null,
    response = "single_html",
    iframe = null,
}) {
    let url = "https://";
    if (subdomain && secondOrigin) {
        url += "{{hosts[alt][www2]}}";
    } else if (subdomain) { // && !second_origin
        url += "{{hosts[][www2]}}";
    } else if (secondOrigin) { // && !subdomain
        url += "{{hosts[alt][]}}";
    } else { // !second_origin && !subdomain
        url += "{{hosts[][]}}";
    }
    url += ":{{ports[https][0]}}";
    url += "/clear-site-data/support/clear-site-data-cache.py";
    url = new URL(url);
    let params = new URLSearchParams();
    params.append("cache_helper", cacheHelper);
    params.append("response", response)
    if (clear !== null) {
        params.append("clear", clear);
    }
    if (clearFirst != null) {
        params.append("clear_first", clearFirst);
    }
    if (cache) {
        params.append("cache", "");
    }
    if (iframe != null) {
        let iframeUrl = getUrl(cacheHelper, iframe);
        params.append("iframe", iframeUrl);
    }
    url.search = params;
    return url.toString();
}

/**
 * Opens test pages sequentially, compares first and last uuid. Makes sure test cleans up properly
 * @param test - test clean up
 * @param {string} firstUuid - uuid returned by first url
 * @param {array[string]} testUrls - array of all urls that should be visited
 * @param {integer} curIdx - index in testUrls that is visited in the current function call
 * @param {function assert_not_equal|assert_equal} assert - function that gets passed first and last
 *        uuid and determines the success of the test case
 * @param {function} resolve - function to call when test case is complete
 * @param {*} options - URL generation options.
 */
function openTestPageHelper(test, firstUuid, testUrls, curIdx, assert, resolve) {
    window.addEventListener("message", test.step_func(e => {
        let curUuid = e.data;
        if (firstUuid === null) {
            firstUuid = curUuid;
        }

        if (curIdx + 1 < testUrls.length) {
            openTestPageHelper(test, firstUuid, testUrls, curIdx + 1, assert, resolve);
        } else {
            // Last Step
            assert(firstUuid, curUuid);
            resolve();
        }
    }), {once: true});

    window.open(testUrls[curIdx]);
}

// Here's the set-up for this test: Step 1 and Step 2 are repeated for each param in params
// Step 1 (main window) Open popup window with url generated with `getUrl`
// Step 2 (first window) Message main window with potentially cached uuid and close popup
// Last Step (main window): Assert first and last uuid not equal due to `clear-site-data: "cache"` header
//
// Basic diagram visualizing how the test works:
//
//     main window opens sequentially:
//             (1)                  (2)                (last) = (1)
//              | Step 1             | Step 3                | Step 4
//              |                    |                       |
//     +--------v---------+   +------v----------+     +------v-----------+
//     | first / second   |   |  Clear Data?    |     |                  |
//     | origin           |   |                 |     |                  |
//     |                  |   |                 |     |                  |
//     | +-iframe-------+ |   | +-(iframe?)---+ | ... | +-iframe-------+ |
//     | | first/second | |   | | Clear Data? | |     | |              | |
//     | | origin       | |   | |             | |     | |              | |
//     | +-----------+--+ |   | +-------------+ |     | +-+------------+ |
//     +-------------+----+   +-----------------+     +---+--------------+
//                   |                                    |
//                   | Step 2            +----------------+ Step 5
//                   |                   |
//                   v                   v
//     Last Step: is uuid from (1) different from (last)?
function testCacheClear(test, params, assert) {
    if (params.length < 2) {
        // fail test case
        return new Promise((resolve, reject) => reject());
    }

    const cacheHelper = self.crypto.randomUUID();
    const testUrls = params.map((param) => getUrl(cacheHelper, param));

    return new Promise(resolve => {
        openTestPageHelper(test, null, testUrls, 0, assert, resolve)
    });
}
