/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { config } from "#config.js";
import { NodeJsCrypto } from "#crypto/NodeJsCrypto.js";
import { NodeJsHttpEndpoint } from "#net/NodeJsHttpEndpoint.js";
import { FileStorageDriver } from "#storage/fs/FileStorageDriver.js";
import {
  asError,
  Boot,
  Crypto,
  Entropy,
  Environment,
  Filesystem,
  HttpEndpointFactory,
  ImplementationError,
  LogFormat,
  Logger,
  MemoryStorageDriver,
  Network,
  ServiceBundle,
  StandardCrypto,
  StorageService,
  WalStorageDriver
} from "@matter/general";
import { isBunjs } from "#util/runtimeChecks.js";
import { existsSync, readFileSync } from "node:fs";
import { writeFile } from "node:fs/promises";
import { resolve } from "node:path";
import { NodeJsFilesystem } from "../fs/NodeJsFilesystem.js";
import { NodeJsNetwork } from "../net/NodeJsNetwork.js";
import { ProcessManager } from "./ProcessManager.js";
function NodeJsEnvironment() {
  const env = new Environment("default");
  loadVariables(env);
  configureCrypto(env);
  configureRuntime(env);
  configureStorage(env);
  configureNetwork(env);
  configureFilesystem(env);
  if (!env.vars.has("logger.format") && Logger.format === LogFormat.PLAIN && process.stdin?.isTTY) {
    env.vars.set("logger.format", LogFormat.ANSI);
  }
  ServiceBundle.default.deploy(env);
  config.isInitialized = true;
  return env;
}
function loadVariables(env) {
  const vars = env.vars;
  vars.addConfigStyle(getDefaults(vars));
  if (config.loadProcessEnv) {
    vars.addUnixEnvStyle(process.env);
  }
  if (config.loadProcessArgv) {
    vars.addArgvStyle(process.argv);
  }
  const { configPath, configVars } = loadConfigFile(vars);
  if (config.loadConfigFile) {
    vars.addConfigStyle(configVars);
  }
  if (config.loadProcessEnv) {
    vars.addUnixEnvStyle(process.env);
  }
  if (config.loadProcessArgv) {
    vars.addArgvStyle(process.argv);
  }
  vars.persistConfigValue = async (name, value) => {
    if (value === void 0) {
      delete configVars[name];
    }
    configVars[name] = value;
    await writeFile(configPath, JSON.stringify(configVars, void 0, 4));
  };
}
function rootDirOf(env) {
  return env.vars.get("path.root", ".");
}
function configureCrypto(env) {
  Boot.init(() => {
    if (env.vars.boolean("nodejs.crypto")) {
      let crypto;
      if (!isBunjs()) {
        crypto = new NodeJsCrypto();
      } else {
        crypto = new StandardCrypto(global.crypto);
      }
      env.set(Entropy, crypto);
      env.set(Crypto, crypto);
      return;
    }
    if (Environment.default.has(Entropy)) {
      env.set(Entropy, Environment.default.get(Entropy));
    }
    if (Environment.default.has(Crypto)) {
      env.set(Crypto, Environment.default.get(Crypto));
    }
  });
}
function configureNetwork(env) {
  Boot.init(() => {
    if (env.vars.boolean("nodejs.network")) {
      env.set(Network, new NodeJsNetwork());
      env.set(HttpEndpointFactory, new NodeJsHttpEndpoint.Factory());
      return;
    }
    if (Environment.default.has(Network)) {
      env.set(Network, Environment.default.get(Network));
    }
    if (Environment.default.has(HttpEndpointFactory)) {
      env.set(HttpEndpointFactory, Environment.default.get(HttpEndpointFactory));
    }
  });
}
function configureRuntime(env) {
  const processManager = new ProcessManager(env);
  env.set(ProcessManager, processManager);
}
function configureStorage(env) {
  Boot.init(() => {
    if (env.vars.boolean("nodejs.storage")) {
      const service = env.get(StorageService);
      service.registerDriver(MemoryStorageDriver);
      service.registerDriver(WalStorageDriver);
      service.registerDriver(FileStorageDriver);
      service.registerDriver({
        id: "sqlite",
        async create(namespace) {
          const { SqliteStorageDriver } = await import("#storage/sqlite/index.js");
          return SqliteStorageDriver.create(namespace);
        }
      });
      service.defaultDriver = "file";
      let storageDriver = env.vars.string("storage.driver");
      if (storageDriver && storageDriver.length > 0) {
        service.configuredDriver = storageDriver;
      }
      return;
    }
    if (Environment.default.has(StorageService)) {
      env.set(StorageService, Environment.default.get(StorageService));
    }
  });
}
function configureFilesystem(env) {
  Boot.init(() => {
    if (env.vars.boolean("nodejs.filesystem")) {
      env.set(Filesystem, new NodeJsFilesystem(() => env.vars.get("storage.path", rootDirOf(env))));
      return;
    }
    if (Environment.default.has(Filesystem)) {
      env.set(Filesystem, Environment.default.get(Filesystem));
    }
  });
}
function loadConfigFile(vars) {
  const configPath = vars.get("path.config", "config.json");
  if (!existsSync(configPath)) {
    return { configPath, configVars: {} };
  }
  let configJson;
  try {
    configJson = readFileSync(configPath).toString();
  } catch (e) {
    throw new ImplementationError(`Error reading configuration file ${configPath}: ${asError(e).message}`);
  }
  let configVars;
  try {
    configVars = JSON.parse(configJson);
  } catch (e) {
    throw new ImplementationError(`Error parsing configuration file ${configPath}: ${asError(e).message}`);
  }
  return { configPath, configVars };
}
function getDefaultRoot(envName) {
  if (config.defaultStoragePath !== void 0) {
    return config.defaultStoragePath;
  }
  let matterDir;
  if (process.platform === "win32") {
    matterDir = resolve(process.env.APPDATA ?? ".", "matter");
  } else {
    matterDir = resolve(process.env.HOME ?? ".", ".matter");
  }
  if (envName !== "default") {
    matterDir = `${matterDir}-${envName}`;
  }
  return matterDir;
}
function getDefaults(vars) {
  const envName = vars.get("environment", config.defaultEnvironmentName);
  const rootPath = vars.get("path.root", getDefaultRoot(envName));
  const configPath = resolve(rootPath, vars.get("path.config", config.defaultConfigFilePath));
  return {
    environment: envName,
    path: {
      root: rootPath,
      config: configPath
    },
    runtime: {
      signals: config.trapProcessSignals,
      exitcode: config.setProcessExitCodeOnError,
      unhandlederrors: config.trapUnhandledErrors
    },
    nodejs: {
      crypto: config.installCrypto,
      filesystem: config.installFilesystem,
      network: config.installNetwork,
      storage: config.initializeStorage
    },
    storage: {
      driver: config.storageDriver
    }
  };
}
export {
  NodeJsEnvironment,
  getDefaults,
  loadConfigFile
};
//# sourceMappingURL=NodeJsEnvironment.js.map
