// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '//resources/cr_elements/cr_icon_button/cr_icon_button.js';
import '//resources/cr_elements/icons.html.js';
import './icons.html.js';
import { CrLitElement } from '//resources/lit/v3_0/lit.rollup.js';
import { getCss } from './trace_report.css.js';
import { getHtml } from './trace_report.html.js';
import { Notification, NotificationType } from './trace_report_list.js';
import { downloadTraceData, getTokenAsUuidString } from './trace_util.js';
import { TracesBrowserProxy } from './traces_browser_proxy.js';
import { ReportUploadState, SkipUploadReason } from './traces_internals.mojom-webui.js';
export class TraceReportElement extends CrLitElement {
    static get is() {
        return 'trace-report';
    }
    static get styles() {
        return getCss();
    }
    render() {
        return getHtml.bind(this)();
    }
    static get properties() {
        return {
            trace: { type: Object },
            isHeader: { type: Boolean },
            isLoading: { type: Boolean },
        };
    }
    traceReportProxy_ = TracesBrowserProxy.getInstance();
    #trace_accessor_storage = null;
    get trace() { return this.#trace_accessor_storage; }
    set trace(value) { this.#trace_accessor_storage = value; }
    #isHeader_accessor_storage = false;
    get isHeader() { return this.#isHeader_accessor_storage; }
    set isHeader(value) { this.#isHeader_accessor_storage = value; }
    #isLoading_accessor_storage = false;
    get isLoading() { return this.#isLoading_accessor_storage; }
    set isLoading(value) { this.#isLoading_accessor_storage = value; }
    onCopyUuidClick_() {
        if (!this.trace) {
            return;
        }
        // Get the text field
        navigator.clipboard.writeText(getTokenAsUuidString(this.trace.uuid));
    }
    getTraceSize_(trace) {
        if (trace.totalSize < 1) {
            return '0 Bytes';
        }
        let displayedSize = Number(trace.totalSize);
        const k = 1024;
        const sizes = ['Bytes', 'KB', 'MB', 'GB'];
        let i = 0;
        for (i; displayedSize >= k && i < 3; i++) {
            displayedSize /= k;
        }
        return `${displayedSize.toFixed(2)} ${sizes[i]}`;
    }
    getSkipReason_(trace) {
        // Keep this in sync with the values of SkipUploadReason in
        // tracereport.mojom
        const skipReasonMap = [
            'None',
            'Size limit exceeded',
            'Not anonymized',
            'Scenario quota exceeded',
            'Upload timed out',
            'Local scenario',
        ];
        return skipReasonMap[trace.skipReason] ?? 'Could not get the skip reason';
    }
    onCopyScenarioClick_() {
        if (!this.trace) {
            return;
        }
        // Get the text field
        navigator.clipboard.writeText(this.trace.scenarioName);
    }
    onCopyUploadRuleClick_() {
        if (!this.trace) {
            return;
        }
        // Get the text field
        navigator.clipboard.writeText(this.trace.uploadRuleName);
    }
    isManualUploadDisabled_(trace) {
        return this.isLoading ||
            trace.skipReason === SkipUploadReason.kNotAnonymized;
    }
    dateToString_(mojoTime) {
        // The JS Date() is based off of the number of milliseconds since
        // the UNIX epoch (1970-01-01 00::00:00 UTC), while |internalValue|
        // of the base::Time (represented in mojom.Time) represents the
        // number of microseconds since the Windows FILETIME epoch
        // (1601-01-01 00:00:00 UTC). This computes the final JS time by
        // computing the epoch delta and the conversion from microseconds to
        // milliseconds.
        const windowsEpoch = Date.UTC(1601, 0, 1, 0, 0, 0, 0);
        const unixEpoch = Date.UTC(1970, 0, 1, 0, 0, 0, 0);
        // |epochDeltaInMs| equals to
        // base::Time::kTimeTToMicrosecondsOffset.
        const epochDeltaInMs = unixEpoch - windowsEpoch;
        const timeInMs = Number(mojoTime.internalValue) / 1000;
        // Define the format in which the date string is going to be displayed.
        return new Date(timeInMs - epochDeltaInMs)
            .toLocaleString(
        /*locales=*/ undefined, {
            hour: 'numeric',
            minute: 'numeric',
            month: 'short',
            day: 'numeric',
            year: 'numeric',
            hour12: true,
        });
    }
    async onDownloadTraceClick_() {
        if (!this.trace) {
            return;
        }
        this.isLoading = true;
        const { trace } = await this.traceReportProxy_.handler.downloadTrace(this.trace.uuid);
        if (trace !== null) {
            this.downloadData_(trace, this.trace.uuid);
        }
        else {
            this.dispatchToast_(`Failed to download trace ${getTokenAsUuidString(this.trace.uuid)}.`);
        }
        this.isLoading = false;
    }
    downloadData_(data, uuid) {
        if (data.invalidBuffer) {
            this.dispatchToast_(`Invalid buffer received for ${getTokenAsUuidString(uuid)}.`);
            return;
        }
        try {
            downloadTraceData(data, uuid);
        }
        catch (e) {
            this.dispatchToast_(`Unable to create blob from trace data for ${getTokenAsUuidString(uuid)}.`);
        }
    }
    async onDeleteTraceClick_() {
        if (!this.trace) {
            return;
        }
        this.isLoading = true;
        const { success } = await this.traceReportProxy_.handler.deleteSingleTrace(this.trace.uuid);
        if (!success) {
            this.dispatchToast_(`Failed to delete ${getTokenAsUuidString(this.trace.uuid)}.`);
        }
        else {
            this.dispatchReloadRequest_();
        }
    }
    async onUploadTraceClick_() {
        if (!this.trace) {
            return;
        }
        this.isLoading = true;
        const { success } = await this.traceReportProxy_.handler.userUploadSingleTrace(this.trace.uuid);
        if (!success) {
            this.dispatchToast_(`Failed to upload trace ${getTokenAsUuidString(this.trace.uuid)}.`);
        }
        else {
            this.dispatchReloadRequest_();
        }
        this.isLoading = false;
    }
    uploadStateEqual_(trace, state) {
        return trace.uploadState === state;
    }
    dispatchToast_(message) {
        this.fire('show-toast', new Notification(NotificationType.ERROR, message));
    }
    isDownloadDisabled_(trace) {
        return this.isLoading || !trace.hasTraceContent;
    }
    getDownloadTooltip_(trace) {
        return trace.hasTraceContent ? 'Download Trace' : 'Trace expired';
    }
    dispatchReloadRequest_() {
        this.fire('refresh-traces-request');
    }
    getStateCssClass_(trace) {
        switch (trace.uploadState) {
            case ReportUploadState.kNotUploaded:
                return 'state-default';
            case ReportUploadState.kPending:
            case ReportUploadState.kPending_UserRequested:
                return 'state-pending';
            case ReportUploadState.kUploaded:
                return 'state-success';
            default:
                return '';
        }
    }
    getStateText_(trace) {
        switch (trace.uploadState) {
            case ReportUploadState.kNotUploaded:
                return `Upload skipped: ${this.getSkipReason_(trace)}`;
            case ReportUploadState.kPending:
                return 'Pending upload';
            case ReportUploadState.kPending_UserRequested:
                return 'Pending upload: User requested';
            case ReportUploadState.kUploaded:
                return `Uploaded: ${this.dateToString_(trace.uploadTime)}`;
            default:
                return '';
        }
    }
}
customElements.define(TraceReportElement.is, TraceReportElement);
