/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module RpcInterface
 */
import { BentleyStatus, Logger } from "@itwin/core-bentley";
import { CommonLoggerCategory } from "../../CommonLoggerCategory";
import { IModelError } from "../../IModelError";
import { RpcProtocolEvent } from "../core/RpcConstants";
import { RpcInvocation } from "../core/RpcInvocation";
import { WebAppRpcRequest } from "./WebAppRpcRequest";
/* eslint-disable @typescript-eslint/no-deprecated */
/** @internal */
const BACKEND = Symbol.for("@itwin.WebAppRpcLogging.Backend");
const FRONTEND = Symbol.for("@itwin.WebAppRpcLogging.Frontend");
/** @internal */
export class WebAppRpcLogging {
    static initializeBackend(instance) {
        globalThis[BACKEND] = instance;
    }
    static initializeFrontend(instance) {
        globalThis[FRONTEND] = instance;
    }
    static get backend() {
        const instance = globalThis[BACKEND];
        if (typeof (instance) === "undefined") {
            throw new IModelError(BentleyStatus.ERROR, "Backend logging is not initialized.");
        }
        return instance;
    }
    static get frontend() {
        const instance = globalThis[FRONTEND];
        if (typeof (instance) === "undefined") {
            throw new IModelError(BentleyStatus.ERROR, "Frontend logging is not initialized.");
        }
        return instance;
    }
    static async logProtocolEvent(event, object) {
        if (object instanceof WebAppRpcRequest) {
            await WebAppRpcLogging.frontend.logProtocolEvent(event, object);
        }
        else if (object instanceof RpcInvocation) {
            await WebAppRpcLogging.backend.logProtocolEvent(event, object);
        }
    }
    getRpcInterfaceName(g) {
        return (typeof g === "string") ? g : g.interfaceName;
    }
    findPathIds(path) {
        let iTwinId = "";
        let iModelId = "";
        const tokens = path.split("/");
        for (let i = 0; i !== tokens.length; ++i) {
            // For backwards compatibility, find old "context" or current "iTwin" terminology
            if ((/^context$/i).test(tokens[i]) || (/^itwin$/i).test(tokens[i])) {
                iTwinId = tokens[i + 1] || "";
            }
            if ((/^imodel$/i).test(tokens[i])) {
                iModelId = tokens[i + 1] || "";
            }
        }
        return { iTwinId, iModelId };
    }
    buildOperationDescriptor(operation) {
        if (!operation) {
            return "unknown.unknown";
        }
        const interfaceName = typeof (operation.interfaceDefinition) === "string" ? operation.interfaceDefinition : operation.interfaceDefinition.interfaceName;
        const operationName = operation.operationName;
        return `${interfaceName}.${operationName}`;
    }
    logRequest(loggerCategory, message, object) {
        const operationDescriptor = this.buildOperationDescriptor(object.operation);
        const pathIds = this.findPathIds(object.path);
        Logger.logTrace(loggerCategory, `${message}.${operationDescriptor}`, () => ({
            method: object.method,
            path: object.path,
            operation: object.operation.operationName,
            rpcInterface: this.getRpcInterfaceName(object.operation.interfaceDefinition),
            // Alert! The following properties are required by Bentley DevOps standards. Do not change their names!
            ActivityId: object.id, // eslint-disable-line @typescript-eslint/naming-convention
            TimeElapsed: ("elapsed" in object) ? object.elapsed : 0, // eslint-disable-line @typescript-eslint/naming-convention
            MachineName: this.getHostname(), // eslint-disable-line @typescript-eslint/naming-convention
            ...pathIds,
        }));
    }
    logResponse(loggerCategory, message, object, status, elapsed) {
        const operationDescriptor = this.buildOperationDescriptor(object.operation);
        const pathIds = this.findPathIds(object.path);
        Logger.logTrace(loggerCategory, `${message}.${operationDescriptor}`, () => ({
            method: object.method,
            path: object.path,
            operation: object.operation.operationName,
            rpcInterface: this.getRpcInterfaceName(object.operation.interfaceDefinition),
            status,
            // Alert! The following properties are required by Bentley DevOps standards. Do not change their names!
            ActivityId: object.id, // eslint-disable-line @typescript-eslint/naming-convention
            TimeElapsed: elapsed, // eslint-disable-line @typescript-eslint/naming-convention
            MachineName: this.getHostname(), // eslint-disable-line @typescript-eslint/naming-convention
            ...pathIds,
        }));
    }
}
class WebAppRpcLoggingFrontend extends WebAppRpcLogging {
    async logProtocolEvent(event, object) {
        switch (event) {
            case RpcProtocolEvent.RequestCreated: return this.logRequest(CommonLoggerCategory.RpcInterfaceFrontend, "RpcInterface.frontend.request", object);
            case RpcProtocolEvent.ResponseLoaded: return this.logResponse(CommonLoggerCategory.RpcInterfaceFrontend, "RpcInterface.frontend.response", object, object.metadata.status, object.elapsed);
            case RpcProtocolEvent.ConnectionErrorReceived: return this.logErrorFrontend("RpcInterface.frontend.connectionError", object);
            case RpcProtocolEvent.ConnectionAborted: return this.logErrorFrontend("RpcInterface.frontend.connectionAborted", object);
        }
    }
    getHostname() {
        if (globalThis.window) {
            return globalThis.window.location.host;
        }
        else {
            return "imodeljs-mobile";
        }
    }
    logErrorFrontend(message, request) {
        const operationDescriptor = this.buildOperationDescriptor(request.operation);
        const pathIds = this.findPathIds(request.path);
        Logger.logInfo(CommonLoggerCategory.RpcInterfaceFrontend, `${message}.${operationDescriptor}`, () => ({
            method: request.method,
            path: request.path,
            // Alert! The following properties are required by Bentley DevOps standards. Do not change their names!
            ActivityId: request.id, // eslint-disable-line @typescript-eslint/naming-convention
            MachineName: this.getHostname(), // eslint-disable-line @typescript-eslint/naming-convention
            ...pathIds,
        }));
    }
}
WebAppRpcLogging.initializeFrontend(new WebAppRpcLoggingFrontend());
//# sourceMappingURL=WebAppRpcLogging.js.map