// Copyright 2011 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 'chrome://resources/js/assert.js';
import { addWebUiListener, removeWebUiListener } from 'chrome://resources/js/cr.js';
import { aboutInfo } from './about.js';
import { getAllNodes, requestIncludeSpecificsInitialState, requestListOfTypes } from './chrome_sync.js';
import { log } from './sync_log.js';
const dumpToTextButton = document.querySelector('#dump-to-text');
assert(dumpToTextButton);
const dataDump = document.querySelector('#data-dump');
assert(dataDump);
dumpToTextButton.addEventListener('click', function () {
    // TODO(akalin): Add info like Chrome version, OS, date dumped, etc.
    let data = '';
    data += '======\n';
    data += 'Status\n';
    data += '======\n';
    data += JSON.stringify(aboutInfo, null, 2);
    data += '\n';
    data += '\n';
    data += '===\n';
    data += 'Log\n';
    data += '===\n';
    data += JSON.stringify(log.entries, null, 2);
    data += '\n';
    dataDump.textContent = data;
});
const allFields = [
    'ID',
    'IS_UNSYNCED',
    'IS_UNAPPLIED_UPDATE',
    'BASE_VERSION',
    'BASE_VERSION_TIME',
    'SERVER_VERSION',
    'SERVER_VERSION_TIME',
    'PARENT_ID',
    'SERVER_PARENT_ID',
    'IS_DEL',
    'SERVER_IS_DEL',
    'dataType',
    'SERVER_SPECIFICS',
    'SPECIFICS',
];
function versionToDateString(version) {
    // TODO(mmontgomery): ugly? Hacky? Is there a better way?
    const epochLength = Date.now().toString().length;
    const epochTime = parseInt(version.slice(0, epochLength), 10);
    const date = new Date(epochTime);
    return date.toString();
}
/**
 * @param node A JavaScript represenation of a sync entity.
 * @return A string representation of the sync entity.
 */
function serializeNode(node) {
    const includeSpecifics = document.querySelector('#include-specifics');
    assert(includeSpecifics);
    return allFields.map(function (field) {
        let fieldVal;
        if (field === 'SERVER_VERSION_TIME') {
            const version = node['SERVER_VERSION'];
            if (version != null) {
                fieldVal = versionToDateString(version);
            }
        }
        if (field === 'BASE_VERSION_TIME') {
            const version = node['BASE_VERSION'];
            if (version != null) {
                fieldVal = versionToDateString(version);
            }
        }
        else if ((field === 'SERVER_SPECIFICS' || field === 'SPECIFICS') &&
            (!includeSpecifics.checked)) {
            fieldVal = 'REDACTED';
        }
        else if ((field === 'SERVER_SPECIFICS' || field === 'SPECIFICS') &&
            includeSpecifics.checked) {
            fieldVal = JSON.stringify(node[field]);
        }
        else {
            fieldVal = node[field];
        }
        return fieldVal || '';
    });
}
/**
 * @param type The name of a sync data type.
 * @return True if the type's checkbox is selected.
 */
function isSelectedDatatype(type) {
    const checkbox = document.querySelector(`#${CSS.escape(type)}`);
    assert(checkbox);
    return checkbox.checked;
}
function makeBlobUrl(data) {
    const textBlob = new Blob([data], { type: 'octet/stream' });
    const blobUrl = window.URL.createObjectURL(textBlob);
    return blobUrl;
}
function makeDownloadName() {
    // Format is sync-data-dump-$epoch-$year-$month-$day-$OS.csv.
    const now = new Date();
    const friendlyDate = [now.getFullYear(), now.getMonth() + 1, now.getDate()].join('-');
    const name = [
        'sync-data-dump',
        friendlyDate,
        Date.now(),
        navigator.platform,
    ].join('-');
    return [name, 'csv'].join('.');
}
function makeDateUserAgentHeader() {
    const now = new Date();
    const userAgent = window.navigator.userAgent;
    const dateUaHeader = [now.toISOString(), userAgent].join(',');
    return dateUaHeader;
}
/**
 * Builds a summary of current state and exports it as a downloaded file.
 *
 * @param nodesMap Summary of local state by data type.
 */
function triggerDataDownload(nodesMap) {
    // Prepend a header with ISO date and useragent.
    const output = [makeDateUserAgentHeader()];
    output.push('=====');
    const aboutInfoString = JSON.stringify(aboutInfo, null, 2);
    output.push(aboutInfoString);
    // Filter out non-selected types.
    const selectedTypesNodes = nodesMap.filter(function (x) {
        return isSelectedDatatype(x.type);
    });
    // Serialize the remaining nodes and add them to the output.
    selectedTypesNodes.forEach(function (typeNodes) {
        output.push('=====');
        output.push(typeNodes.nodes.map(serializeNode).join('\n'));
    });
    const outputString = output.join('\n');
    const anchor = document.querySelector('#dump-to-file-anchor');
    assert(anchor);
    anchor.href = makeBlobUrl(outputString);
    anchor.download = makeDownloadName();
    anchor.click();
}
function onAllTypesCheckboxClicked(types) {
    const allTypesCheckbox = document.querySelector('#all-types');
    assert(allTypesCheckbox);
    const isChecked = allTypesCheckbox.checked;
    types.forEach(type => {
        const checkbox = document.querySelector(`#${CSS.escape(type)}`);
        assert(checkbox);
        checkbox.checked = isChecked;
    });
    onIndividualTypeCheckboxClicked(types);
}
function onIndividualTypeCheckboxClicked(types) {
    const allTypesCheckbox = document.querySelector('#all-types');
    assert(allTypesCheckbox);
    const allChecked = types.every(isSelectedDatatype);
    const someChecked = types.some(isSelectedDatatype);
    allTypesCheckbox.checked = allChecked;
    allTypesCheckbox.indeterminate = someChecked && !allChecked;
}
function createTypesCheckboxes(types) {
    const containerElt = document.querySelector('#node-type-checkboxes');
    assert(containerElt);
    const allTypesDiv = document.createElement('div');
    const allTypesCheckbox = document.createElement('input');
    allTypesCheckbox.id = 'all-types';
    allTypesCheckbox.type = 'checkbox';
    allTypesCheckbox.checked = true;
    allTypesCheckbox.addEventListener('click', () => onAllTypesCheckboxClicked(types.slice()));
    allTypesDiv.appendChild(allTypesCheckbox);
    const allTypesLabel = document.createElement('label');
    // Assigning to label.for doesn't work.
    allTypesLabel.setAttribute('for', allTypesCheckbox.id);
    allTypesLabel.innerText = 'All types';
    allTypesDiv.appendChild(allTypesLabel);
    containerElt.appendChild(allTypesDiv);
    containerElt.appendChild(document.createElement('hr'));
    types.map(function (type) {
        const div = document.createElement('div');
        const checkbox = document.createElement('input');
        checkbox.id = type;
        checkbox.type = 'checkbox';
        checkbox.checked = true;
        checkbox.addEventListener('click', () => onIndividualTypeCheckboxClicked(types.slice()));
        div.appendChild(checkbox);
        const label = document.createElement('label');
        // Assigning to label.for doesn't work.
        label.setAttribute('for', checkbox.id);
        label.innerText = type;
        div.appendChild(label);
        containerElt.appendChild(div);
    });
}
let listOfTypesListener = null;
function onReceivedListOfTypes(response) {
    const types = response.types;
    types.sort();
    createTypesCheckboxes(types);
    assert(listOfTypesListener);
    removeWebUiListener(listOfTypesListener);
}
function onReceivedIncludeSpecificsInitialState(response) {
    const captureSpecifics = document.querySelector('#capture-specifics');
    assert(captureSpecifics);
    captureSpecifics.checked = response.includeSpecifics;
}
document.addEventListener('DOMContentLoaded', function () {
    listOfTypesListener =
        addWebUiListener('onReceivedListOfTypes', onReceivedListOfTypes);
    requestListOfTypes();
    addWebUiListener('onReceivedIncludeSpecificsInitialState', onReceivedIncludeSpecificsInitialState);
    requestIncludeSpecificsInitialState();
});
const dumpToFileLink = document.querySelector('#dump-to-file');
assert(dumpToFileLink);
dumpToFileLink.addEventListener('click', function () {
    getAllNodes(triggerDataDownload);
});
