import * as Platform from "@effect/platform";
import * as Schema from "@effect/schema/Schema";
import * as Effect from "effect/Effect";
import * as Function from "effect/Function";
import * as Option from "effect/Option";
import * as Predicate from "effect/Predicate";
import * as ReadonlyArray from "effect/ReadonlyArray";
import * as Tuple from "effect/Tuple";
import * as InternetSchemas from "../InternetSchemas.js";
import * as WireguardConfig from "../WireguardConfig.js";
import * as WireguardInterface from "../WireguardInterface.js";
import * as WireguardKey from "../WireguardKey.js";
/** @internal */
export const fromConfigFile = file => Effect.gen(function* (λ) {
  const fs = yield* λ(Platform.FileSystem.FileSystem);
  const fsConfig = yield* λ(fs.readFileString(file));
  const iniConfigDecoded = WireguardConfig.WireguardIniConfig(fsConfig);
  const iniConfigEncoded = yield* λ(Schema.encode(WireguardConfig.WireguardIniConfig)(iniConfigDecoded));
  const config = yield* λ(Schema.decode(WireguardConfig.WireguardConfig)(iniConfigEncoded));
  return config;
});
/** @internal */
export const writeToFile = /*#__PURE__*/Function.dual(2, (file, config) => Effect.gen(function* (λ) {
  const path = yield* λ(Platform.Path.Path);
  const fs = yield* λ(Platform.FileSystem.FileSystem);
  const configEncoded = yield* λ(Schema.encode(WireguardConfig.WireguardConfig)(config));
  const iniConfigDecoded = yield* λ(Schema.decode(WireguardConfig.WireguardIniConfig)(configEncoded));
  yield* λ(fs.makeDirectory(path.dirname(file), {
    recursive: true
  }));
  yield* λ(fs.writeFileString(file, iniConfigDecoded));
}));
/** @internal */
export const generateP2PConfigs = (aliceData, bobData, cidrBlock) => Effect.gen(function* (λ) {
  const hubEndpoint = aliceData;
  const spokeEndpoints = ReadonlyArray.make(bobData);
  const [aliceConfig, [bobConfig]] = Predicate.isUndefined(cidrBlock) ? yield* λ(generateHubSpokeConfigs(hubEndpoint, spokeEndpoints)) : yield* λ(generateHubSpokeConfigs(hubEndpoint, spokeEndpoints, cidrBlock));
  return Tuple.make(aliceConfig, bobConfig);
});
/** @internal */
export const generateHubSpokeConfigs = (hubData, spokeData, cidrBlock) => Effect.gen(function* (λ) {
  // Convert the setup data to the correct format if needed
  const isSetupData = Predicate.isUndefined(cidrBlock);
  const hubSetupData = isSetupData ? hubData : Tuple.make(hubData, "");
  const spokeSetupData = isSetupData ? spokeData : ReadonlyArray.map(spokeData, spoke => Tuple.make(spoke, ""));
  // Generate the keys and parse the setup data
  const hubKeys = WireguardKey.generateKeyPair();
  const hubsData = yield* λ(Schema.decode(InternetSchemas.SetupData)(hubSetupData));
  const spokesData = yield* λ(Effect.all(ReadonlyArray.map(spokeSetupData, spoke => Schema.decode(InternetSchemas.SetupData)(spoke))));
  // This hub peer config will be added to all the spoke interface configs
  const hubPeerConfig = {
    PublicKey: hubKeys.publicKey,
    Endpoint: Tuple.getFirst(hubsData),
    AllowedIPs: [{
      ipv4: Tuple.getSecond(hubsData),
      mask: 32
    }]
  };
  // All these spoke peer configs will be added to the hub interface config
  const spokePeerConfigs = ReadonlyArray.map(spokesData, spoke => {
    const keys = WireguardKey.generateKeyPair();
    const peerConfig = {
      Endpoint: Tuple.getFirst(spoke),
      PublicKey: keys.publicKey,
      AllowedIPs: [{
        ipv4: InternetSchemas.IPv4(Tuple.getSecond(spoke)),
        mask: InternetSchemas.IPv4CidrMask(32)
      }]
    };
    return Tuple.make(Tuple.make(keys.privateKey, spoke), peerConfig);
  });
  // The hub interface config will have all the spoke peer configs
  const hubConfig = yield* λ(Schema.decode(WireguardConfig.WireguardConfig)({
    PrivateKey: hubKeys.privateKey,
    Address: {
      ipv4: Tuple.getSecond(hubsData),
      mask: 24
    },
    ListenPort: Tuple.getFirst(hubsData).listenPort,
    Peers: ReadonlyArray.map(spokePeerConfigs, Tuple.getSecond)
  }));
  // Each spoke interface config will have the hub peer config
  const spokeConfigs = yield* λ(Function.pipe(spokePeerConfigs, ReadonlyArray.map(([[privateKey, spoke]]) => Schema.decode(WireguardConfig.WireguardConfig)({
    PrivateKey: privateKey,
    Peers: [hubPeerConfig],
    Address: {
      ipv4: Tuple.getSecond(spoke),
      mask: 24
    },
    ListenPort: Tuple.getFirst(spoke).listenPort
  })), Effect.allWith()));
  return Tuple.make(hubConfig, spokeConfigs);
});
/** @internal */
export const up = /*#__PURE__*/Function.dual(3, (config, options, interfaceObject) => Function.pipe(interfaceObject, Option.fromNullable, Option.map(Effect.succeed), Option.getOrElse(() => WireguardInterface.WireguardInterface.getNextAvailableInterface), Effect.flatMap(io => io.up(config, options))));
/** @internal */
export const upScoped = /*#__PURE__*/Function.dual(3, (config, options, interfaceObject) => Function.pipe(interfaceObject, Option.fromNullable, Option.map(Effect.succeed), Option.getOrElse(() => WireguardInterface.WireguardInterface.getNextAvailableInterface), Effect.flatMap(io => io.upScoped(config, options))));
//# sourceMappingURL=wireguardConfig.js.map