import * as vscode from "vscode";

export class LaunchUriHandler implements vscode.UriHandler {
  async handleUri(uri: vscode.Uri) {
    try {
      const params = new URLSearchParams(uri.query);
      if (uri.path == "/start") {
        // Some properties have default values
        let debugConfig: vscode.DebugConfiguration = {
          type: "lldb-dap",
          request: "launch",
          name: "",
        };
        // The `config` parameter allows providing a complete JSON-encoded configuration
        const configJson = params.get("config");
        if (configJson !== null) {
          Object.assign(debugConfig, JSON.parse(configJson));
        }
        // Furthermore, some frequently used parameters can also be provided as separate parameters
        const stringKeys = [
          "name",
          "request",
          "program",
          "cwd",
          "debuggerRoot",
        ];
        const numberKeys = ["pid"];
        const arrayKeys = [
          "args",
          "initCommands",
          "preRunCommands",
          "stopCommands",
          "exitCommands",
          "terminateCommands",
          "launchCommands",
          "attachCommands",
        ];
        for (const key of stringKeys) {
          const value = params.get(key);
          if (value) {
            debugConfig[key] = value;
          }
        }
        for (const key of numberKeys) {
          const value = params.get(key);
          if (value) {
            debugConfig[key] = Number(value);
          }
        }
        for (const key of arrayKeys) {
          // `getAll()` returns an array of strings.
          const value = params.getAll(key);
          if (value) {
            debugConfig[key] = value;
          }
        }
        // Report an error if we received any unknown parameters
        const supportedKeys = new Set<string>(
          ["config"].concat(stringKeys).concat(numberKeys).concat(arrayKeys),
        );
        const presentKeys = new Set<string>(params.keys());
        // FIXME: Use `Set.difference` as soon as ES2024 is widely available
        const unknownKeys = new Set<string>();
        for (const k of presentKeys.keys()) {
          if (!supportedKeys.has(k)) {
            unknownKeys.add(k);
          }
        }
        if (unknownKeys.size > 0) {
          throw new Error(
            `Unsupported URL parameters: ${Array.from(unknownKeys.keys()).join(", ")}`,
          );
        }
        // Prodide a default for the config name
        const defaultName =
          debugConfig.request == "launch"
            ? "URL-based Launch"
            : "URL-based Attach";
        debugConfig.name =
          debugConfig.name || debugConfig.program || defaultName;
        // Force the type to `lldb-dap`. We don't want to allow launching any other
        // Debug Adapters using this URI scheme.
        if (debugConfig.type != "lldb-dap") {
          throw new Error(`Unsupported debugger type: ${debugConfig.type}`);
        }
        await vscode.debug.startDebugging(undefined, debugConfig);
      } else {
        throw new Error(`Unsupported Uri path: ${uri.path}`);
      }
    } catch (err) {
      if (err instanceof Error) {
        await vscode.window.showErrorMessage(
          `Failed to handle lldb-dap URI request: ${err.message}`,
        );
      } else {
        await vscode.window.showErrorMessage(
          `Failed to handle lldb-dap URI request: ${JSON.stringify(err)}`,
        );
      }
    }
  }
}
