// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// 
import 'chrome://resources/js/action_link.js';
import '/strings.m.js';
import { assert } from 'chrome://resources/js/assert.js';
import { addWebUiListener } from 'chrome://resources/js/cr.js';
import { loadTimeData } from 'chrome://resources/js/load_time_data.js';
import { appendParam, getRequiredElement } from 'chrome://resources/js/util.js';
/* Id for tracking automatic refresh of crash list.  */
let refreshCrashListId = undefined;
/**
 * Requests the list of crashes from the backend.
 */
function requestCrashes() {
    chrome.send('requestCrashList');
}
/**
 * Format filesize in appropriate display units.
 */
function formatBytes(bytes) {
    const k = 1024;
    const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
    let unitAmount = bytes;
    let unit = 0;
    for (unit; unitAmount >= k && unit < units.length - 1; unit++) {
        unitAmount /= k;
    }
    const unitAmountLocalized = unitAmount.toLocaleString(undefined, // Default locale.
    { maximumFractionDigits: 2 });
    return `${unitAmountLocalized} ${units[unit]}`;
}
// Keep in sync with components/crash/core/browser/crashes_ui_util.cc.
var State;
(function (State) {
    State["NOT_UPLOADED"] = "not_uploaded";
    State["PENDING"] = "pending";
    State["PENDING_USER_REQUESTED"] = "pending_user_requested";
    State["UPLOADED"] = "uploaded";
})(State || (State = {}));
/**
 * Callback from backend with the list of crashes. Builds the UI.
 */
function updateCrashList({ enabled, dynamicBackend, manualUploads, crashes, version, os, isGoogleAccount, }) {
    getRequiredElement('crashesCount').textContent = loadTimeData.getStringF('crashCountFormat', crashes.length.toLocaleString());
    const crashList = getRequiredElement('crashList');
    getRequiredElement('disabledMode').hidden = enabled;
    getRequiredElement('crashUploadStatus').hidden = !enabled || !dynamicBackend;
    const template = crashList.querySelector('template');
    assert(template);
    // Clear any previous list.
    crashList.querySelectorAll('.crash-row').forEach((elm) => elm.remove());
    const productName = loadTimeData.getString('shortProductName');
    for (const crash of crashes) {
        if (crash.local_id === '') {
            crash.local_id = productName;
        }
        const clone = template.content.cloneNode(true);
        if (crash.state !== State.UPLOADED) {
            const crashRow = clone.querySelector('.crash-row');
            assert(crashRow);
            crashRow.classList.add('not-uploaded');
        }
        const uploaded = crash.state === State.UPLOADED;
        // Some clients do not distinguish between capture time and upload time,
        // so use the latter if the former is not available.
        const captureTime = clone.querySelector('.capture-time');
        assert(captureTime);
        captureTime.textContent = loadTimeData.getStringF('crashCaptureTimeFormat', crash.capture_time || crash.upload_time || '');
        const localIdCell = clone.querySelector('.local-id .value');
        assert(localIdCell);
        localIdCell.textContent = crash.local_id;
        let stateText = '';
        switch (crash.state) {
            case State.NOT_UPLOADED:
                stateText = loadTimeData.getString('crashStatusNotUploaded');
                break;
            case State.PENDING:
                stateText = loadTimeData.getString('crashStatusPending');
                break;
            case State.PENDING_USER_REQUESTED:
                stateText = loadTimeData.getString('crashStatusPendingUserRequested');
                break;
            case State.UPLOADED:
                stateText = loadTimeData.getString('crashStatusUploaded');
                break;
            default:
                continue; // Unknown state.
        }
        const statusCell = clone.querySelector('.status .value');
        assert(statusCell);
        statusCell.textContent = stateText;
        const uploadId = clone.querySelector('.upload-id');
        assert(uploadId);
        const uploadTime = clone.querySelector('.upload-time');
        assert(uploadTime);
        const sendNowButton = clone.querySelector('.send-now');
        assert(sendNowButton);
        const fileBugButton = clone.querySelector('.file-bug');
        assert(fileBugButton);
        if (uploaded) {
            const uploadIdValue = uploadId.querySelector('.value');
            assert(uploadIdValue);
            if (isGoogleAccount) {
                const crashLink = document.createElement('a');
                crashLink.href = `https://goto.google.com/crash/${crash.id}`;
                crashLink.target = '_blank';
                crashLink.textContent = crash.id;
                uploadIdValue.appendChild(crashLink);
            }
            else {
                uploadIdValue.textContent = crash.id;
            }
            const uploadTimeCell = uploadTime.querySelector('.value');
            assert(uploadTimeCell);
            uploadTimeCell.textContent = crash.upload_time || '';
            sendNowButton.remove();
            fileBugButton.onclick = () => fileBug(crash.id, os, version);
        }
        else {
            uploadId.remove();
            uploadTime.remove();
            fileBugButton.remove();
            // Do not allow crash submission if the Chromium build does not support
            // it, or if the user already requested it.
            if (!manualUploads || crash.state === State.PENDING_USER_REQUESTED) {
                sendNowButton.remove();
            }
            sendNowButton.onclick = (_e) => {
                sendNowButton.disabled = true;
                chrome.send('requestSingleCrashUpload', [crash.local_id]);
            };
        }
        const fileSize = clone.querySelector('.file-size');
        assert(fileSize);
        if (crash.file_size === undefined) {
            fileSize.remove();
        }
        else {
            const fileSizeCell = fileSize.querySelector('.value');
            assert(fileSizeCell);
            fileSizeCell.textContent = formatBytes(crash.file_size);
        }
        crashList.appendChild(clone);
    }
    getRequiredElement('noCrashes').hidden = crashes.length !== 0;
}
/**
 * Opens a new tab/window to report the crash to crbug.
 * @param The crash report ID.
 * @param The OS name.
 * @param The product version.
 */
function fileBug(crashId, os, version) {
    const commentLines = [
        'IMPORTANT: Your crash has already been automatically reported ' +
            'to our crash system. Please file this bug only if you can provide ' +
            'more information about it.',
        '',
        '',
        'Chrome Version: ' + version,
        'Operating System: ' + os,
        '',
        'URL (if applicable) where crash occurred:',
        '',
        'Can you reproduce this crash?',
        '',
        'What steps will reproduce this crash? (If it\'s not ' +
            'reproducible, what were you doing just before the crash?)',
        '1.',
        '2.',
        '3.',
        '',
        '****DO NOT CHANGE BELOW THIS LINE****',
        'Crash ID: crash/' + crashId,
    ];
    const params = {
        template: 'Crash Report',
        comment: commentLines.join('\n'),
        // TODO(scottmg): Use add_labels to add 'User-Submitted' rather than
        // duplicating the template's labels (the first two) once
        // https://bugs.chromium.org/p/monorail/issues/detail?id=1488 is done.
        labels: 'Restrict-View-EditIssue,Stability-Crash,User-Submitted,Pri-3,Type-Bug',
    };
    let href = 'https://bugs.chromium.org/p/chromium/issues/entry';
    for (const param in params) {
        href = appendParam(href, param, params[param]);
    }
    window.open(href);
}
/**
 * Request crashes get uploaded in the background.
 */
function requestCrashUpload() {
    // Don't need locking with this call because the system crash reporter
    // has locking built into itself.
    chrome.send('requestCrashUpload');
    // Trigger a refresh in 5 seconds.  Clear any previous requests.
    clearTimeout(refreshCrashListId);
    refreshCrashListId = setTimeout(requestCrashes, 5000);
}
/**
 * Toggles hiding/showing the developer details of a crash report, depending
 * on the value of the check box.
 */
function toggleDevDetails(e) {
    getRequiredElement('crashList')
        .classList.toggle('showing-dev-details', e.target.checked);
}
document.addEventListener('DOMContentLoaded', function () {
    addWebUiListener('update-crash-list', updateCrashList);
    getRequiredElement('uploadCrashes').onclick = requestCrashUpload;
    getRequiredElement('showDevDetails').onclick = toggleDevDetails;
    requestCrashes();
});
