// 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 * as Helpers from '../helpers/helpers.js';
import * as Types from '../types/types.js';
/**
 * There are two metadata events that we care about.
 * => AuctionWorkletRunningInProcess tells us which process the Auction Worklet
 *    has taken to run in.
 * => AuctionWorkletDoneWithProcess tells us when the worklet is done with that
 *    process. This is less useful - but in the future we might want to surface
 *    this information so we still parse and return the event.
 *
 * It is important to note that the top level PID on these events is NOT the
 * PID that the worklet is running on; instead we have to look at its
 * args.data.pid property, which is the PID of the process that it is running
 * on.
 *
 * For any given RunningInProcess event, we would typically expect to see a
 * DoneWithProcess event, however this is not guaranteed, especially as users
 * can record any chunk of time in DevTools.
 *
 * Similarly, it is also possible to see a DoneWithProcess event without a
 * RunningInProcess event, if the user started recording after the auction
 * worklets started. Therefore we are happy to create
 * SyntheticAuctionWorklets as long as we see just one of these events.
 *
 * If we do get two events and need to pair them, we can use the
 * args.data.target property, which is a string ID shared by both
 * events.
 */
let runningInProcessEvents = new Map();
let doneWithProcessEvents = new Map();
// Keyed by the PID defined in  `args.data.pid` on AuctionWorklet trace events..
let createdSyntheticEvents = new Map();
// Each AuctonWorklet takes over a process and has 2 threads (that we care
// about and want to show as tracks):
// 1. A CrUtilityMain thread which is known as the "control process".
// 2. A AuctionV8HelperThread which is the actual auction worklet and will be
//    either a "Seller" or a "Bidder"
// To detect these we look for the metadata thread_name events. We key these by
// PID so that we can easily look them up later without having to loop through.
let utilityThreads = new Map();
let v8HelperThreads = new Map();
export function reset() {
    runningInProcessEvents = new Map();
    doneWithProcessEvents = new Map();
    createdSyntheticEvents = new Map();
    utilityThreads = new Map();
    v8HelperThreads = new Map();
}
export function handleEvent(event) {
    if (Types.Events.isAuctionWorkletRunningInProcess(event)) {
        runningInProcessEvents.set(event.args.data.pid, event);
        return;
    }
    if (Types.Events.isAuctionWorkletDoneWithProcess(event)) {
        doneWithProcessEvents.set(event.args.data.pid, event);
        return;
    }
    if (Types.Events.isThreadName(event)) {
        if (event.args.name === 'auction_worklet.CrUtilityMain') {
            utilityThreads.set(event.pid, event);
            return;
        }
        if (event.args.name === 'AuctionV8HelperThread') {
            v8HelperThreads.set(event.pid, event);
        }
    }
}
function workletType(input) {
    switch (input) {
        case 'seller':
            return "seller" /* Types.Events.AuctionWorkletType.SELLER */;
        case 'bidder':
            return "bidder" /* Types.Events.AuctionWorkletType.BIDDER */;
        default:
            return "unknown" /* Types.Events.AuctionWorkletType.UNKNOWN */;
    }
}
/**
 * We cannot make the full event without knowing the type of event, but we can
 * create everything other than the `args` field, as those are identical
 * regardless of the type of event.
 */
function makeSyntheticEventBase(event) {
    return Helpers.SyntheticEvents.SyntheticEventsManager
        .registerSyntheticEvent({
        rawSourceEvent: event,
        name: 'SyntheticAuctionWorklet',
        s: "t" /* Types.Events.Scope.THREAD */,
        cat: event.cat,
        tid: event.tid,
        ts: event.ts,
        ph: "I" /* Types.Events.Phase.INSTANT */,
        pid: event.args.data.pid,
        host: event.args.data.host,
        target: event.args.data.target,
        type: workletType(event.args.data.type),
    });
}
export async function finalize() {
    // Loop through the utility threads we found to create the worklet events. We
    // expect each worklet to have a utility thread, so we can use them as the
    // root of our list of worklets.
    for (const [pid, utilityThreadNameEvent] of utilityThreads) {
        const v8HelperEvent = v8HelperThreads.get(pid);
        if (!v8HelperEvent) {
            // Bad trace data - AuctionWorklets are expected to always have both threads.
            continue;
        }
        const runningEvent = runningInProcessEvents.get(pid);
        const doneWithEvent = doneWithProcessEvents.get(pid);
        // We can create a worklet from either the runningEvent or doneWithEvent -
        // we do not need both. We cannot express that to TypeScript with an early
        // return here, so instead we set the event initially to null, and then
        // create it from either the running event or the doneWith event. If it is
        // still null after this, that means neither event was found, and we drop
        // the worklet as we do not have enough information to create the synthetic
        // event.
        let syntheticEvent = null;
        if (runningEvent) {
            syntheticEvent = {
                ...makeSyntheticEventBase(runningEvent),
                args: {
                    data: {
                        runningInProcessEvent: runningEvent,
                        utilityThread: utilityThreadNameEvent,
                        v8HelperThread: v8HelperEvent,
                    },
                },
            };
            if (doneWithEvent) {
                syntheticEvent.args.data.doneWithProcessEvent = doneWithEvent;
            }
        }
        else if (doneWithEvent) {
            syntheticEvent = {
                ...makeSyntheticEventBase(doneWithEvent),
                args: {
                    data: {
                        doneWithProcessEvent: doneWithEvent,
                        utilityThread: utilityThreadNameEvent,
                        v8HelperThread: v8HelperEvent,
                    },
                },
            };
            if (runningEvent) {
                syntheticEvent.args.data.runningInProcessEvent = runningEvent;
            }
        }
        if (syntheticEvent === null) {
            continue;
        }
        createdSyntheticEvents.set(pid, syntheticEvent);
    }
}
export function data() {
    return {
        worklets: createdSyntheticEvents,
    };
}
//# sourceMappingURL=AuctionWorkletsHandler.js.map