/**
 * @since 1.0.0
 */
import * as ParseResult from "@effect/schema/ParseResult";
import * as Schema from "@effect/schema/Schema";
import * as Effect from "effect/Effect";
import * as Either from "effect/Either";
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 Stream from "effect/Stream";
import * as String from "effect/String";
import * as net from "node:net";
/**
 * An operating system port number.
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 * import { Port } from "the-wireguard-effect/InternetSchemas"
 *
 * const port: Port = Port(8080)
 * assert.strictEqual(port, 8080)
 *
 * const decodePort = Schema.decodeSync(Port)
 * assert.strictEqual(decodePort(8080), 8080)
 *
 * assert.throws(() => decodePort(65536))
 * assert.doesNotThrow(() => decodePort(8080))
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const Port = /*#__PURE__*/Function.pipe(Schema.Int, /*#__PURE__*/Schema.between(0, 2 ** 16 - 1), /*#__PURE__*/Schema.identifier("Port"), /*#__PURE__*/Schema.description("A port number"), /*#__PURE__*/Schema.brand("Port"));
/**
 * An IPv4 address.
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 * import { IPv4 } from "the-wireguard-effect/InternetSchemas"
 *
 * const ipv4: IPv4 = IPv4("1.1.1.1")
 * assert.strictEqual(ipv4, "1.1.1.1")
 *
 * const decodeIPv4 = Schema.decodeSync(IPv4)
 * assert.strictEqual(decodeIPv4("1.1.1.1"), "1.1.1.1")
 *
 * assert.throws(() => decodeIPv4("1.1.a.1"))
 * assert.doesNotThrow(() => decodeIPv4("1.1.1.1"))
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const IPv4 = /*#__PURE__*/Function.pipe(Schema.string, /*#__PURE__*/Schema.filter((s, _options, ast) => net.isIPv4(s) ? Option.none() : Option.some(new ParseResult.Type(ast, s))), /*#__PURE__*/Schema.identifier("IPv4"), /*#__PURE__*/Schema.description("An ipv4 address"), /*#__PURE__*/Schema.brand("IPv4"));
/**
 * An IPv6 address.
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 * import { IPv6 } from "the-wireguard-effect/InternetSchemas"
 *
 * const ipv6: IPv6 = IPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334")
 * assert.strictEqual(ipv6, "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
 *
 * const decodeIPv6 = Schema.decodeSync(IPv6)
 * assert.deepStrictEqual(
 *      decodeIPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
 *      "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
 * )
 *
 * assert.throws(() => decodeIPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334:"))
 * assert.throws(() => decodeIPv6("2001::85a3::0000::0370:7334"))
 * assert.doesNotThrow(() => decodeIPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334"))
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const IPv6 = /*#__PURE__*/Function.pipe(Schema.string, /*#__PURE__*/Schema.filter((s, _options, ast) => net.isIPv6(s) ? Option.none() : Option.some(new ParseResult.Type(ast, s))), /*#__PURE__*/Schema.identifier("IPv6"), /*#__PURE__*/Schema.description("An ipv6 address"), /*#__PURE__*/Schema.brand("IPv6"));
/**
 * An IP address, which is either an IPv4 or IPv6 address.
 *
 * @see {@link IPv4}
 * @see {@link IPv6}
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 * import { Address } from "the-wireguard-effect/InternetSchemas"
 *
 * const address1: Address = Address("1.1.1.1")
 * const address2: Address = Address("2001:0db8:85a3:0000:0000:8a2e:0370:7334")
 *
 * const decodeAddress = Schema.decodeSync(Address)
 * assert.throws(() => decodeAddress("1.1.b.1"))
 * assert.throws(() => decodeAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334:"))
 * assert.doesNotThrow(() => decodeAddress("1.1.1.2"))
 * assert.doesNotThrow(() => decodeAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334"))
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const Address = /*#__PURE__*/Function.pipe( /*#__PURE__*/Schema.union(IPv4, IPv6), /*#__PURE__*/Schema.identifier("Address"), /*#__PURE__*/Schema.description("An ipv4 or ipv6 address"), /*#__PURE__*/Schema.brand("Address"));
/**
 * An IPv4 address as a bigint, helpful for some cidr and subnet related calculations.
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 * import { IPv4Bigint } from "the-wireguard-effect/InternetSchemas"
 *
 * const decodeIPv4Bigint = Schema.decodeSync(IPv4Bigint)
 * assert.deepStrictEqual(
 *      decodeIPv4Bigint("1.1.1.1"),
 *     { value: 16843009n, family: "ipv4" }
 * )
 *
 * const encodeIPv4Bigint = Schema.encodeSync(IPv4Bigint)
 * assert.strictEqual(
 *      encodeIPv4Bigint({ value: 16843009n, family: "ipv4" }),
 *      "1.1.1.1"
 * )
 *
 * assert.throws(() => decodeIPv4Bigint("1.1.1.1000"))
 * assert.doesNotThrow(() => decodeIPv4Bigint("2.2.2.2"))
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const IPv4Bigint = /*#__PURE__*/Schema.transformOrFail(IPv4, Schema.struct({
  value: Schema.bigintFromSelf,
  family: Schema.literal("ipv4")
}),
// When decoding, we know this is a valid IPv4 coming in so
// there is no need to check for parsing errors.
(address, _options, _ast) => Function.pipe(address, String.split("."), ReadonlyArray.map(s => Number.parseInt(s, 10)), ReadonlyArray.map(n => n.toString(16)), ReadonlyArray.map(String.padStart(2, "0")), ReadonlyArray.join(""), hex => BigInt(`0x${hex}`), bigint => ({
  value: bigint,
  family: "ipv4"
}), Effect.succeed),
// When encoding, the bigint value is not guaranteed to be a
// valid ip address, so we might fail when encoding.
(data, _options, _ast) => {
  const padded = data.value.toString(16).replace(/:/g, "").padStart(8, "0");
  const groups = [];
  for (let i = 0; i < 8; i += 2) {
    const h = padded.slice(i, i + 2);
    groups.push(parseInt(h, 16));
  }
  return Schema.decodeEither(IPv4)(groups.join(".")).pipe(Either.mapLeft(({
    error
  }) => error));
}).annotations({
  identifier: "IPv4Bigint",
  description: "An ipv4 address as a bigint"
});
/**
 * An IPv6 address as a bigint, helpful for some cidr and subnet related calculations.
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 * import { IPv6Bigint } from "the-wireguard-effect/InternetSchemas"
 *
 * const decodeIPv6Bigint = Schema.decodeSync(IPv6Bigint)
 * assert.deepStrictEqual(
 *      decodeIPv6Bigint("2001:db8:85a3::8a2e:370:7334"),
 *      { value: 42540766452641154071740215577757643572n, family: "ipv6" }
 * )
 *
 * const encodeIPv6Bigint = Schema.encodeSync(IPv6Bigint)
 * assert.strictEqual(
 *      encodeIPv6Bigint({ value: 42540766452641154071740215577757643572n, family: "ipv6" }),
 *      "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
 * )
 *
 * assert.throws(() => decodeIPv6Bigint("2001:0db8:85a3:0000:0000:8a2e:0370:7334:"))
 * assert.doesNotThrow(() => decodeIPv6Bigint("2001:0db8:85a3:0000:0000:8a2e:0370:7334"))
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const IPv6Bigint = /*#__PURE__*/Schema.transformOrFail(IPv6, Schema.struct({
  value: Schema.bigintFromSelf,
  family: Schema.literal("ipv6")
}),
// When decoding, errors could arise when we try to collapse groups
(address, _options, ast) => {
  function paddedHex(octet) {
    return parseInt(octet, 16).toString(16).padStart(4, "0");
  }
  let groups = [];
  const halves = address.split("::");
  if (halves.length === 2) {
    let first = halves[0].split(":");
    let last = halves[1].split(":");
    if (first.length === 1 && first[0] === "") {
      first = [];
    }
    if (last.length === 1 && last[0] === "") {
      last = [];
    }
    const remaining = 8 - (first.length + last.length);
    if (!remaining) {
      return Effect.fail(new ParseResult.Type(ast, "Error parsing groups"));
    }
    groups = groups.concat(first);
    for (let i = 0; i < remaining; i++) {
      groups.push("0");
    }
    groups = groups.concat(last);
  } else if (halves.length === 1) {
    groups = address.split(":");
  } else {
    return Effect.fail(new ParseResult.Type(ast, "Too many :: groups found"));
  }
  groups = groups.map(group => parseInt(group, 16).toString(16));
  if (groups.length !== 8) {
    return Effect.fail(new ParseResult.Type(ast, "Invalid number of groups"));
  }
  const value = BigInt(`0x${groups.map(paddedHex).join("")}`);
  return Effect.succeed({
    value,
    family: "ipv6"
  });
},
// When encoding, the bigint value is not guaranteed to be a
// valid ip address, so we might fail when encoding.
(data, _options, _ast) => {
  const hex = data.value.toString(16).padStart(32, "0");
  const groups = [];
  for (let i = 0; i < 8; i++) {
    groups.push(hex.slice(i * 4, (i + 1) * 4));
  }
  return Schema.decodeEither(IPv6)(groups.join(":")).pipe(Either.mapLeft(({
    error
  }) => error));
}).annotations({
  identifier: "IPv6Bigint",
  description: "An ipv6 address as a bigint"
});
/**
 * An IP address as a bigint, helpful for some cidr and subnet related calculations.
 *
 * @see {@link IPv4Bigint}
 * @see {@link IPv6Bigint}
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 * import { BigintFromAddress } from "the-wireguard-effect/InternetSchemas"
 *
 * const address1 = Schema.decodeSync(BigintFromAddress)("1.1.1.1")
 * const address2 = Schema.decodeSync(BigintFromAddress)("2001:0db8:85a3:0000:0000:8a2e:0370:7334")
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const BigintFromAddress = /*#__PURE__*/Function.pipe( /*#__PURE__*/Schema.union(IPv4Bigint, IPv6Bigint), /*#__PURE__*/Schema.identifier("BigintFromAddress"), /*#__PURE__*/Schema.description("An ipv4 or ipv6 address as a bigint"));
/**
 * An ipv4 cidr mask, which is a number between 0 and 32.
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 * import { IPv4CidrMask } from "the-wireguard-effect/InternetSchemas"
 *
 * const mask: IPv4CidrMask = IPv4CidrMask(24)
 * assert.strictEqual(mask, 24)
 *
 * const decodeMask = Schema.decodeSync(IPv4CidrMask)
 * assert.strictEqual(decodeMask(24), 24)
 *
 * assert.throws(() => IPv4CidrMask(33))
 * assert.doesNotThrow(() => IPv4CidrMask(0))
 * assert.doesNotThrow(() => IPv4CidrMask(32))
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const IPv4CidrMask = /*#__PURE__*/Function.pipe(Schema.Int, /*#__PURE__*/Schema.between(0, 32), /*#__PURE__*/Schema.identifier("IPv4CidrMask"), /*#__PURE__*/Schema.description("An ipv4 cidr mask"), /*#__PURE__*/Schema.brand("IPv4CidrMask"));
/**
 * An ipv6 cidr mask, which is a number between 0 and 128.
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 * import { IPv6CidrMask } from "the-wireguard-effect/InternetSchemas"
 *
 * const mask: IPv6CidrMask = IPv6CidrMask(64)
 * assert.strictEqual(mask, 64)
 *
 * const decodeMask = Schema.decodeSync(IPv6CidrMask)
 * assert.strictEqual(decodeMask(64), 64)
 *
 * assert.throws(() => IPv6CidrMask(129))
 * assert.doesNotThrow(() => IPv6CidrMask(0))
 * assert.doesNotThrow(() => IPv6CidrMask(128))
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const IPv6CidrMask = /*#__PURE__*/Function.pipe(Schema.Int, /*#__PURE__*/Schema.between(0, 128), /*#__PURE__*/Schema.identifier("IPv6CidrMask"), /*#__PURE__*/Schema.description("An ipv6 cidr mask"), /*#__PURE__*/Schema.brand("IPv6CidrMask"));
/**
 * Internal helper representation of a cidr range so that we can do
 * transformations to and from it as we cannot represent a stream
 * using @effect/schema.
 *
 * @since 1.0.0
 * @category Datatypes
 */
export class CidrBlockInternal extends Schema.Class("CidrBlockInternal")({
  ip: Address,
  mask: Schema.union(IPv4CidrMask, IPv6CidrMask),
  family: Schema.union(Schema.literal("ipv4"), Schema.literal("ipv6")),
  /**
   * The first address in the range given by this address' subnet, often referred to as the Network Address.
   */
  networkAddress: Address,
  /**
   * The last address in the range given by this address' subnet, often referred to as the Broadcast Address.
   */
  broadcastAddress: Address
}) {
  networkAddressBigInt = Schema.decodeSync(BigintFromAddress)(this.networkAddress);
  broadcastAddressBigInt = Schema.decodeSync(BigintFromAddress)(this.broadcastAddress);
  /**
   * A stream of all addresses in the range given by this address' subnet.
   *
   * @since 1.0.0
   */
  get range() {
    const {
      value: minValue
    } = this.networkAddressBigInt;
    const {
      value: maxValue
    } = this.broadcastAddressBigInt;
    const stream = Function.pipe(Stream.iterate(minValue, n => n + 1n), Stream.takeWhile(n => n <= maxValue), Stream.map(n => ({
      value: n,
      family: this.family
    })), Stream.mapEffect(Schema.encode(BigintFromAddress)), Stream.mapEffect(Schema.decode(Address)));
    return stream;
  }
  get total() {
    const {
      value: minValue
    } = this.networkAddressBigInt;
    const {
      value: maxValue
    } = this.broadcastAddressBigInt;
    return maxValue - minValue + 1n;
  }
}
/**
 * A cidr block, which is an IP address followed by a slash and then a subnet mask.
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 *
 * import {
 *      CidrBlock,
 *      IPv4,
 *      IPv4CidrMask,
 *      IPv6,
 *      IPv6CidrMask
 * } from "the-wireguard-effect/InternetSchemas"
 *
 * const block1 = Schema.decodeSync(CidrBlock)("192.168.1.1/24")
 * assert.strictEqual(block1.mask, 24)
 * assert.strictEqual(block1.total, 256n)
 * assert.strictEqual(block1.family, "ipv4")
 * assert.strictEqual(block1.ip, "192.168.1.1")
 * assert.strictEqual(block1.networkAddress, "192.168.1.0")
 * assert.strictEqual(block1.broadcastAddress, "192.168.1.255")
 *
 * const block2 = Schema.decodeSync(CidrBlock)("2001:db8:85a3::8a2e:370:7334/64")
 * assert.strictEqual(block2.mask, 64)
 * assert.strictEqual(block2.family, "ipv6")
 * assert.strictEqual(block2.total, 18446744073709551616n)
 * assert.strictEqual(block2.ip, "2001:db8:85a3::8a2e:370:7334")
 * assert.strictEqual(block2.networkAddress, "2001:0db8:85a3:0000:0000:0000:0000:0000")
 * assert.strictEqual(block2.broadcastAddress, "2001:0db8:85a3:0000:ffff:ffff:ffff:ffff")
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const CidrBlock = /*#__PURE__*/Function.pipe( /*#__PURE__*/Schema.transformOrFail( /*#__PURE__*/Schema.union( /*#__PURE__*/Schema.struct({
  ipv4: IPv4,
  mask: IPv4CidrMask
}), /*#__PURE__*/Schema.struct({
  ipv6: IPv6,
  mask: IPv6CidrMask
}), /*#__PURE__*/Schema.templateLiteral(Schema.string, /*#__PURE__*/Schema.literal("/"), Schema.number)), CidrBlockInternal, (data, _options, _ast) => Effect.gen(function* (λ) {
  const [ip, mask] = Predicate.isString(data) ? data.split("/") : "ipv4" in data ? [data.ipv4, `${data.mask}`] : [data.ipv6, `${data.mask}`];
  const ipParsed = yield* λ(Schema.decode(Schema.union(IPv4, IPv6))(ip));
  const family = String.includes(".")(ipParsed) ? "ipv4" : "ipv6";
  const maskParsed = family === "ipv4" ? yield* λ(Schema.decode(Schema.compose(Schema.NumberFromString, IPv4CidrMask))(mask)) : yield* λ(Schema.decode(Schema.compose(Schema.NumberFromString, IPv6CidrMask))(mask));
  const bits = family === "ipv4" ? 32 : 128;
  const bigIntegerAddress = yield* λ(Schema.decode(BigintFromAddress)(ip));
  const intermediate = bigIntegerAddress.value.toString(2).padStart(bits, "0").slice(0, maskParsed);
  const networkAddressString = intermediate + "0".repeat(bits - maskParsed);
  const networkAddressBigInt = BigInt(`0b${networkAddressString}`);
  const networkAddress = yield* λ(Schema.encode(BigintFromAddress)({
    value: networkAddressBigInt,
    family
  }));
  const broadcastAddressString = intermediate + "1".repeat(bits - maskParsed);
  const broadcastAddressBigInt = BigInt(`0b${broadcastAddressString}`);
  const broadcastAddress = yield* λ(Schema.encode(BigintFromAddress)({
    value: broadcastAddressBigInt,
    family
  }));
  return yield* λ(Schema.decode(CidrBlockInternal)({
    family,
    ip: ipParsed,
    mask: maskParsed,
    networkAddress,
    broadcastAddress
  }));
}).pipe(Effect.mapError(({
  error
}) => error)), ({
  ip,
  mask
}) => Effect.succeed(`${ip}/${mask}`)), /*#__PURE__*/Schema.identifier("CidrBlock"), /*#__PURE__*/Schema.description("A cidr block"), /*#__PURE__*/Schema.brand("CidrBlock"));
/**
 * An IPv4 wireguard endpoint, which consists of an IPv4 address followed by a
 * nat port then an optional local port. If only one port is provided, it is
 * assumed that the nat port and listen port are the same.
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 *
 * import {
 *      Port,
 *      IPv4,
 *      IPv4Endpoint
 * } from "the-wireguard-effect/InternetSchemas"
 *
 * const endpoint1 = Schema.decodeSync(IPv4Endpoint)("1.2.3.4:51820")
 * const endpoint2 = Schema.decodeSync(IPv4Endpoint)("1.2.3.4:51820:41820")
 *
 * const endpoint3 = Schema.decodeSync(IPv4Endpoint)({
 *      ip: "1.2.3.4",
 *      port: 51820,
 * })
 *
 * const endpoint4: IPv4Endpoint = IPv4Endpoint({
 *      ip: IPv4("1.2.3.4"),
 *      natPort: Port(51820),
 *      listenPort: Port(41820)
 * })
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const IPv4Endpoint = /*#__PURE__*/Function.pipe( /*#__PURE__*/Schema.transformOrFail( /*#__PURE__*/Schema.union( /*#__PURE__*/Schema.struct({
  ip: IPv4,
  port: Port
}), /*#__PURE__*/Schema.struct({
  ip: IPv4,
  natPort: Port,
  listenPort: Port
}), /*#__PURE__*/Schema.templateLiteral(Schema.string, /*#__PURE__*/Schema.literal(":"), Schema.number), /*#__PURE__*/Schema.templateLiteral(Schema.string, /*#__PURE__*/Schema.literal(":"), Schema.number, /*#__PURE__*/Schema.literal(":"), Schema.number)), /*#__PURE__*/Schema.struct({
  ip: IPv4,
  natPort: Port,
  listenPort: Port
}), (data, _options, _ast) => Effect.gen(function* (λ) {
  const isObjectInput = !Predicate.isString(data);
  if (isObjectInput) return "port" in data ? {
    ip: data.ip,
    natPort: data.port,
    listenPort: data.port
  } : {
    ip: data.ip,
    natPort: data.natPort,
    listenPort: data.listenPort
  };
  const portDecoder = Schema.decode(Schema.compose(Schema.NumberFromString, Port));
  const [ip, natPort, listenPort] = data.split(":");
  const ipParsed = yield* λ(Schema.decode(IPv4)(ip));
  const natPortParsed = yield* λ(portDecoder(natPort));
  const listenPortParsed = Predicate.isNotUndefined(listenPort) ? yield* λ(portDecoder(listenPort)) : natPortParsed;
  return {
    ip: ipParsed,
    natPort: natPortParsed,
    listenPort: listenPortParsed
  };
}).pipe(Effect.mapError(({
  error
}) => error)), ({
  ip,
  natPort,
  listenPort
}) => Effect.succeed(`${ip}:${natPort}:${listenPort}`)), /*#__PURE__*/Schema.identifier("IPv4Endpoint"), /*#__PURE__*/Schema.description("An ipv4 wireguard endpoint"), /*#__PURE__*/Schema.brand("IPv4Endpoint"));
/**
 * An IPv6 wireguard endpoint, which consists of an IPv6 address in square
 * brackets followed by a nat port then an optional local port. If only one
 * port is provided, it is assumed that the nat port and listen port are the
 * same.
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 *
 * import {
 *      Port,
 *      IPv6,
 *      IPv6Endpoint
 * } from "the-wireguard-effect/InternetSchemas"
 *
 * const endpoint1 = Schema.decodeSync(IPv6Endpoint)("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820")
 * const endpoint2 = Schema.decodeSync(IPv6Endpoint)("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820:41820")
 *
 * const endpoint3 = Schema.decodeSync(IPv6Endpoint)({
 *      ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
 *      port: 51820,
 * })
 *
 * const endpoint4: IPv6Endpoint = IPv6Endpoint({
 *      ip: IPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
 *      natPort: Port(51820),
 *      listenPort: Port(41820)
 * })
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const IPv6Endpoint = /*#__PURE__*/Function.pipe( /*#__PURE__*/Schema.transformOrFail( /*#__PURE__*/Schema.union( /*#__PURE__*/Schema.struct({
  ip: IPv6,
  port: Port
}), /*#__PURE__*/Schema.struct({
  ip: IPv6,
  natPort: Port,
  listenPort: Port
}), /*#__PURE__*/Schema.templateLiteral( /*#__PURE__*/Schema.literal("["), Schema.string, /*#__PURE__*/Schema.literal("]"), /*#__PURE__*/Schema.literal(":"), Schema.number), /*#__PURE__*/Schema.templateLiteral( /*#__PURE__*/Schema.literal("["), Schema.string, /*#__PURE__*/Schema.literal("]"), /*#__PURE__*/Schema.literal(":"), Schema.number, /*#__PURE__*/Schema.literal(":"), Schema.number)), /*#__PURE__*/Schema.struct({
  ip: IPv6,
  natPort: Port,
  listenPort: Port
}), (data, _options, _ast) => Effect.gen(function* (λ) {
  const isObjectInput = !Predicate.isString(data);
  if (isObjectInput) return "port" in data ? {
    ip: data.ip,
    natPort: data.port,
    listenPort: data.port
  } : {
    ip: data.ip,
    natPort: data.natPort,
    listenPort: data.listenPort
  };
  const portDecoder = Schema.decode(Schema.compose(Schema.NumberFromString, Port));
  const [ip, ports] = data.split("]");
  const [_, natPort, listenPort] = ports.split(":");
  const ipParsed = yield* λ(Schema.decode(IPv6)(ip.slice(1)));
  const natPortParsed = yield* λ(portDecoder(natPort));
  const listenPortParsed = Predicate.isNotUndefined(listenPort) ? yield* λ(portDecoder(listenPort)) : natPortParsed;
  return {
    ip: ipParsed,
    natPort: natPortParsed,
    listenPort: listenPortParsed
  };
}).pipe(Effect.mapError(({
  error
}) => error)), ({
  ip,
  natPort,
  listenPort
}) => Effect.succeed(`[${ip}]:${natPort}:${listenPort}`)), /*#__PURE__*/Schema.identifier("IPv6Endpoint"), /*#__PURE__*/Schema.description("An ipv6 wireguard endpoint"), /*#__PURE__*/Schema.brand("IPv6Endpoint"));
/**
 * A wireguard endpoint, which is either an IPv4 or IPv6 endpoint.
 *
 * @see {@link IPv4Endpoint}
 * @see {@link IPv6Endpoint}
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 *
 * import {
 *      Endpoint,
 *      IPv4,
 *      IPv6,
 *      Port
 * } from "the-wireguard-effect/InternetSchemas"
 *
 * const endpoint1 = Schema.decodeSync(Endpoint)("1.2.3.4:51820")
 * const endpoint2 = Schema.decodeSync(Endpoint)("1.2.3.4:51820:41820")
 *
 * const endpoint3 = Schema.decodeSync(Endpoint)({
 *      ip: "1.2.3.4",
 *      port: 51820,
 * })
 *
 * const endpoint4: Endpoint = Endpoint({
 *      ip: IPv4("1.2.3.4"),
 *      natPort: Port(51820),
 *      listenPort: Port(41820),
 * })
 *
 * const endpoint5 = Schema.decodeSync(Endpoint)("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820")
 * const endpoint6 = Schema.decodeSync(Endpoint)("[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820:41820")
 *
 * const endpoint7 = Schema.decodeSync(Endpoint)({
 *      ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
 *      port: 51820,
 * })
 *
 * const endpoint8: Endpoint = Endpoint({
 *      ip: IPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
 *      natPort: Port(51820),
 *      listenPort: Port(41820),
 * })
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const Endpoint = /*#__PURE__*/Function.pipe( /*#__PURE__*/Schema.union(IPv4Endpoint, IPv6Endpoint), /*#__PURE__*/Schema.identifier("Endpoint"), /*#__PURE__*/Schema.description("A wireguard endpoint"), /*#__PURE__*/Schema.brand("Endpoint"));
/**
 * A wireguard setup data, which consists of an endpoint followed by an address.
 *
 * @see {@link Endpoint}
 * @see {@link Address}
 *
 * @example
 * import * as Schema from "@effect/schema/Schema"
 *
 * import {
 *      Address,
 *      Endpoint,
 *      SetupData
 * } from "the-wireguard-effect/InternetSchemas"
 *
 * const setupData1 = Schema.decodeSync(SetupData)(["1.1.1.1:51280", "10.0.0.1"])
 *
 * const address = Schema.decodeSync(Address)("10.0.0.1")
 * const endpoint = Schema.decodeSync(Endpoint)("1.1.1.1:51820")
 * const setupData2: SetupData = SetupData([endpoint, address])
 *
 * @since 1.0.0
 * @category Datatypes
 */
export const SetupData = /*#__PURE__*/Function.pipe( /*#__PURE__*/Schema.tuple(Endpoint, Address), /*#__PURE__*/Schema.identifier("SetupData"), /*#__PURE__*/Schema.description("A wireguard setup data"), /*#__PURE__*/Schema.brand("SetupData"));
//# sourceMappingURL=InternetSchemas.js.map