// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
import * as semver from "semver";
import { ProjectVersionHelper } from "../common/projectVersionHelper";
import { IAttachRequestArgs } from "./debugSessionBase";

export class JsDebugConfigAdapter {
    private static RNVersion_Direct_Debug = "0.76.0";
    public static createDebuggingConfigForPureRN(
        attachArgs: IAttachRequestArgs,
        cdpProxyPort: number,
        sessionId: string,
    ): any {
        return Object.assign({}, JsDebugConfigAdapter.getExistingExtraArgs(attachArgs), {
            type: "pwa-node",
            request: "attach",
            name: "Attach",
            continueOnAttach: true,
            port: cdpProxyPort,
            // The unique identifier of the debug session. It is used to distinguish React Native extension's
            // debug sessions from other ones. So we can save and process only the extension's debug sessions
            // in vscode.debug API methods "onDidStartDebugSession" and "onDidTerminateDebugSession".
            rnDebugSessionId: sessionId,
            // Fixes https://github.com/microsoft/vscode/issues/102042
            resolveSourceMapLocations: ["!**/debuggerWorker.js"],
        });
    }

    public static async createDebuggingConfigForRNHermes(
        attachArgs: IAttachRequestArgs,
        cdpProxyPort: number,
        sessionId: string,
    ) {
        const extraArgs: any = {};
        const versions = await ProjectVersionHelper.getReactNativeVersions(attachArgs.cwd);
        // Handle project file path from 0.76
        if (semver.gte(versions.reactNativeVersion, JsDebugConfigAdapter.RNVersion_Direct_Debug)) {
            extraArgs.sourceMapPathOverrides = {
                "/[metro-project]/*": `${attachArgs.cwd}/*`,
            };
        }

        // Combine source map path between extra arguments and attach arguments
        if (attachArgs.sourceMapPathOverrides) {
            extraArgs.sourceMapPathOverrides = {
                ...extraArgs.sourceMapPathOverrides,
                ...attachArgs.sourceMapPathOverrides,
            };
        }

        return Object.assign({}, JsDebugConfigAdapter.getExistingExtraArgs(attachArgs), extraArgs, {
            type: "pwa-node",
            request: "attach",
            name: "Attach",
            continueOnAttach: true,
            port: cdpProxyPort,
            // The unique identifier of the debug session. It is used to distinguish React Native extension's
            // debug sessions from other ones. So we can save and process only the extension's debug sessions
            // in vscode.debug API methods "onDidStartDebugSession" and "onDidTerminateDebugSession".
            rnDebugSessionId: sessionId,
            // We need to provide js-debug with the "**" pattern, so that it can get source maps over a http URL.
            // We need to allow "**/node_modules/expo/**" path, since Expo source maps URL contains it.
            resolveSourceMapLocations: ["**", "!**/node_modules/!(expo)/**"],
        });
    }

    public static createChromeDebuggingConfig(
        attachArgs: IAttachRequestArgs,
        cdpProxyPort: number,
        pwaSessionName: string,
        sessionId: string,
    ): any {
        const extraArgs: any = {};

        return Object.assign({}, this.getExistingExtraArgs(attachArgs), extraArgs, {
            type: pwaSessionName,
            request: "attach",
            name: "Attach",
            port: cdpProxyPort,
            webRoot: attachArgs.cwd,
            rnDebugSessionId: sessionId,
        });
    }

    private static getExistingExtraArgs(attachArgs: IAttachRequestArgs): any {
        const existingExtraArgs: any = {};
        if (attachArgs.env) {
            existingExtraArgs.env = attachArgs.env;
        }
        if (attachArgs.envFile) {
            existingExtraArgs.envFile = attachArgs.envFile;
        }
        existingExtraArgs.sourceMaps = attachArgs.sourceMaps;
        existingExtraArgs.sourceMapRenames = attachArgs.sourceMapRenames;
        if (attachArgs.sourceMapPathOverrides) {
            existingExtraArgs.sourceMapPathOverrides = attachArgs.sourceMapPathOverrides;
        }
        if (attachArgs.skipFiles) {
            existingExtraArgs.skipFiles = attachArgs.skipFiles;
        }
        if (attachArgs.jsDebugTrace) {
            existingExtraArgs.trace = attachArgs.jsDebugTrace;
        }

        return existingExtraArgs;
    }
}
