/**
 * Internet schemas for wireguard configuration.
 *
 * @since 1.0.0
 */
import * as Array from "effect/Array";
import * as Brand from "effect/Brand";
import * as Duration from "effect/Duration";
import * as Effect from "effect/Effect";
import * as Function from "effect/Function";
import * as HashSet from "effect/HashSet";
import * as ParseResult from "effect/ParseResult";
import * as Predicate from "effect/Predicate";
import * as Record from "effect/Record";
import * as Schema from "effect/Schema";
import * as Stream from "effect/Stream";
import * as String from "effect/String";
import * as Tuple from "effect/Tuple";
import * as net from "node:net";
/** @internal */
export const tail = elements => elements.slice(1);
/** @internal */
export const splitLiteral = (str, delimiter) => str.split(delimiter);
/** @internal */
export const transposeSet = record => Function.pipe(record, Record.map(HashSet.values), Record.map(Array.fromIterable), Record.collect((key, connections) => Array.map(connections, connection => Tuple.make(connection, key))), Array.flatten, Array.groupBy(Tuple.getFirst), Record.map(Array.map(Tuple.getSecond)), Record.map(HashSet.fromIterable));
/**
 * Transforms a `number` of seconds into a `Duration`.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Duration from "effect/Duration";
 *     import * as Schema from "effect/Schema";
 *     import { DurationFromSeconds } from "the-wireguard-effect/InternetSchemas";
 *
 *     const decodeDuration = Schema.decodeSync(DurationFromSeconds);
 *     const duration = decodeDuration(11);
 *     assert.strictEqual(Duration.toSeconds(duration), 11);
 */
export class DurationFromSeconds extends /*#__PURE__*/Schema.transform(Schema.Int, Schema.DurationFromSelf, {
  decode: Duration.seconds,
  encode: Duration.toSeconds
}).annotations({
  identifier: "DurationFromSeconds",
  description: "A duration from a number of seconds"
}) {}
/**
 * Transforms a `string` of seconds into a `Duration`.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Duration from "effect/Duration";
 *     import * as Schema from "effect/Schema";
 *     import { DurationFromSecondsString } from "the-wireguard-effect/InternetSchemas";
 *
 *     const decodeDurationString = Schema.decodeSync(
 *         DurationFromSecondsString
 *     );
 *     const duration = decodeDurationString("12");
 *     assert.strictEqual(Duration.toSeconds(duration), 12);
 */
export class DurationFromSecondsString extends /*#__PURE__*/Schema.compose(Schema.NumberFromString, DurationFromSeconds).annotations({
  identifier: "DurationFromSecondsString",
  description: "A duration from a string of seconds"
}) {}
/**
 * @since 1.0.0
 * @category Branded constructors
 */
export const PortBrand = /*#__PURE__*/Brand.nominal();
/**
 * An operating system port number.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import { Port, PortBrand } from "the-wireguard-effect/InternetSchemas";
 *
 *     const port: PortBrand = PortBrand(8080);
 *     assert.strictEqual(port, 8080);
 *
 *     const decodePort = Schema.decodeSync(Port);
 *     assert.strictEqual(decodePort(8080), 8080);
 *
 *     assert.throws(() => decodePort(65536));
 *     assert.doesNotThrow(() => decodePort(8080));
 */
export const Port = /*#__PURE__*/Schema.Int.pipe(Schema.between(0, 2 ** 16 - 1)).pipe(Schema.fromBrand(PortBrand)).annotations({
  identifier: "Port",
  title: "An OS port number",
  description: "An operating system's port number between 0 and 65535 (inclusive)"
});
/**
 * @since 1.0.0
 * @category Schemas
 */
export const IPv4Family = /*#__PURE__*/Schema.Literal("ipv4").annotations({
  identifier: "IPv4Family",
  description: "An ipv4 family"
});
/**
 * @since 1.0.0
 * @category Branded constructors
 */
export const IPv4Brand = /*#__PURE__*/Brand.nominal();
/**
 * An IPv4 address.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import { IPv4 } from "the-wireguard-effect/InternetSchemas";
 *
 *     const decodeIPv4 = Schema.decodeSync(IPv4);
 *     assert.deepEqual(decodeIPv4("1.1.1.1"), {
 *         family: "ipv4",
 *         ip: "1.1.1.1",
 *     });
 *
 *     assert.throws(() => decodeIPv4("1.1.a.1"));
 *     assert.doesNotThrow(() => decodeIPv4("1.1.1.2"));
 */
export const IPv4 = /*#__PURE__*/Schema.transform(Function.pipe(Schema.String, Schema.filter(str => net.isIPv4(str))), Schema.Struct({
  family: IPv4Family,
  ip: Schema.String.pipe(Schema.fromBrand(IPv4Brand))
}), {
  encode: ({
    ip
  }) => ip,
  decode: ip => ({
    ip,
    family: "ipv4"
  })
}).annotations({
  identifier: "IPv4",
  title: "An ipv4 address",
  description: "An ipv4 address in dot-decimal notation with no leading zeros"
});
/**
 * @since 1.0.0
 * @category Branded constructors
 */
export const IPv4BigintBrand = /*#__PURE__*/Brand.nominal();
/**
 * An IPv4 as a bigint.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import {
 *         IPv4Bigint,
 *         IPv4BigintBrand,
 *     } from "the-wireguard-effect/InternetSchemas";
 *
 *     const x: IPv4BigintBrand = IPv4BigintBrand(748392749382n);
 *     assert.strictEqual(x, 748392749382n);
 *
 *     const decodeIPv4Bigint = Schema.decodeSync(IPv4Bigint);
 *     const encodeIPv4Bigint = Schema.encodeSync(IPv4Bigint);
 *
 *     assert.deepEqual(decodeIPv4Bigint("1.1.1.1"), {
 *         family: "ipv4",
 *         value: 16843009n,
 *     });
 *     assert.deepEqual(decodeIPv4Bigint("254.254.254.254"), {
 *         family: "ipv4",
 *         value: 4278124286n,
 *     });
 *
 *     assert.strictEqual(
 *         encodeIPv4Bigint({
 *             value: IPv4BigintBrand(16843009n),
 *             family: "ipv4",
 *         }),
 *         "1.1.1.1"
 *     );
 *     assert.strictEqual(
 *         encodeIPv4Bigint({
 *             value: IPv4BigintBrand(4278124286n),
 *             family: "ipv4",
 *         }),
 *         "254.254.254.254"
 *     );
 */
export const IPv4Bigint = /*#__PURE__*/Schema.transformOrFail(IPv4, Schema.Struct({
  family: IPv4Family,
  value: Schema.BigIntFromSelf.pipe(Schema.fromBrand(IPv4BigintBrand))
}), {
  encode: ({
    value
  }) => {
    const padded = 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.decode(IPv4)(groups.join(".")).pipe(Effect.mapError(({
      issue
    }) => issue));
  },
  decode: ({
    ip
  }) => Function.pipe(ip, String.split("."), Array.map(s => Number.parseInt(s, 10)), Array.map(n => n.toString(16)), Array.map(String.padStart(2, "0")), Array.join(""), hex => BigInt(`0x${hex}`), value => ({
    value,
    family: "ipv4"
  }), Effect.succeed)
}).annotations({
  identifier: "IPv4Bigint",
  description: "An ipv4 address as a bigint"
});
/**
 * @since 1.0.0
 * @category Schemas
 */
export const IPv6Family = /*#__PURE__*/Schema.Literal("ipv6").annotations({
  identifier: "IPv6Family",
  description: "An ipv6 family"
});
/**
 * @since 1.0.0
 * @category Branded constructors
 */
export const IPv6Brand = /*#__PURE__*/Brand.nominal();
/**
 * An IPv6 address.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import { IPv6 } from "the-wireguard-effect/InternetSchemas";
 *
 *     const decodeIPv6 = Schema.decodeSync(IPv6);
 *     assert.deepEqual(decodeIPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), {
 *         family: "ipv6",
 *         ip: "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")
 *     );
 */
export const IPv6 = /*#__PURE__*/Schema.transform(Function.pipe(Schema.String, Schema.filter(str => net.isIPv6(str))), Schema.Struct({
  family: IPv6Family,
  ip: Schema.String.pipe(Schema.fromBrand(IPv6Brand))
}), {
  encode: ({
    ip
  }) => ip,
  decode: ip => ({
    ip,
    family: "ipv6"
  })
}).annotations({
  identifier: "IPv6",
  description: "An ipv6 address"
});
/**
 * @since 1.0.0
 * @category Branded constructors
 */
export const IPv6BigintBrand = /*#__PURE__*/Brand.nominal();
/**
 * An IPv6 as a bigint.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import {
 *         IPv6Bigint,
 *         IPv6BigintBrand,
 *     } from "the-wireguard-effect/InternetSchemas";
 *
 *     const y: IPv6BigintBrand = IPv6BigintBrand(748392749382n);
 *     assert.strictEqual(y, 748392749382n);
 *
 *     const decodeIPv6Bigint = Schema.decodeSync(IPv6Bigint);
 *     const encodeIPv6Bigint = Schema.encodeSync(IPv6Bigint);
 *
 *     assert.deepEqual(
 *         decodeIPv6Bigint("4cbd:ff70:e62b:a048:686c:4e7e:a68a:c377"),
 *         { value: 102007852745154114519525620108359287671n, family: "ipv6" }
 *     );
 *     assert.deepEqual(
 *         decodeIPv6Bigint("d8c6:3feb:46e6:b80c:5a07:6227:ac19:caf6"),
 *         { value: 288142618299897818094313964584331496182n, family: "ipv6" }
 *     );
 *
 *     assert.deepEqual(
 *         encodeIPv6Bigint({
 *             value: IPv6BigintBrand(102007852745154114519525620108359287671n),
 *             family: "ipv6",
 *         }),
 *         "4cbd:ff70:e62b:a048:686c:4e7e:a68a:c377"
 *     );
 *     assert.deepEqual(
 *         encodeIPv6Bigint({
 *             value: IPv6BigintBrand(288142618299897818094313964584331496182n),
 *             family: "ipv6",
 *         }),
 *         "d8c6:3feb:46e6:b80c:5a07:6227:ac19:caf6"
 *     );
 */
export const IPv6Bigint = /*#__PURE__*/Schema.transformOrFail(IPv6, Schema.Struct({
  family: IPv6Family,
  value: Schema.BigIntFromSelf.pipe(Schema.fromBrand(IPv6BigintBrand))
}), {
  encode: ({
    value
  }) => {
    const hex = 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.decode(IPv6)(groups.join(":")).pipe(Effect.mapError(({
      issue
    }) => issue));
  },
  decode: ({
    ip
  }) => {
    function paddedHex(octet) {
      return parseInt(octet, 16).toString(16).padStart(4, "0");
    }
    let groups = [];
    const halves = ip.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) {
        throw new Error("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 = ip.split(":");
    } else {
      throw new Error("Too many :: groups found");
    }
    groups = groups.map(group => parseInt(group, 16).toString(16));
    if (groups.length !== 8) {
      throw new Error("Invalid number of groups");
    }
    return Effect.succeed({
      value: BigInt(`0x${groups.map(paddedHex).join("")}`),
      family: "ipv6"
    });
  }
}).annotations({
  identifier: "IPv6Bigint",
  description: "An ipv6 address as a bigint"
});
/**
 * @since 1.0.0
 * @category Schemas
 * @see {@link IPv4Family}
 * @see {@link IPv6Family}
 */
export const Family = /*#__PURE__*/Schema.Union(IPv4Family, IPv6Family).annotations({
  identifier: "Family",
  description: "An ipv4 or ipv6 family"
});
/**
 * An IP address, which is either an IPv4 or IPv6 address.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import { Address } from "the-wireguard-effect/InternetSchemas";
 *
 *     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")
 *     );
 *
 * @see {@link IPv4}
 * @see {@link IPv6}
 */
export const Address = /*#__PURE__*/Schema.Union(IPv4, IPv6).annotations({
  identifier: "Address",
  description: "An ipv4 or ipv6 address"
});
/**
 * An IP address as a bigint.
 *
 * @since 1.0.0
 * @category Schemas
 */
export const AddressBigint = /*#__PURE__*/Schema.Union(IPv4Bigint, IPv6Bigint).annotations({
  identifier: "AddressBigint",
  description: "An ipv4 or ipv6 address as a bigint"
});
/**
 * @since 1.0.0
 * @category Branded constructors
 */
export const IPv4CidrMaskBrand = /*#__PURE__*/Brand.nominal();
/**
 * An ipv4 cidr mask, which is a number between 0 and 32.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import {
 *         IPv4CidrMask,
 *         IPv4CidrMaskBrand,
 *     } from "the-wireguard-effect/InternetSchemas";
 *
 *     const mask: IPv4CidrMaskBrand = IPv4CidrMaskBrand(24);
 *     assert.strictEqual(mask, 24);
 *
 *     const decodeMask = Schema.decodeSync(IPv4CidrMask);
 *     assert.strictEqual(decodeMask(24), 24);
 *
 *     assert.throws(() => decodeMask(33));
 *     assert.doesNotThrow(() => decodeMask(0));
 *     assert.doesNotThrow(() => decodeMask(32));
 */
export const IPv4CidrMask = /*#__PURE__*/Schema.Int.pipe(Schema.between(0, 32)).pipe(Schema.fromBrand(IPv4CidrMaskBrand)).annotations({
  identifier: "IPv4CidrMask",
  description: "An ipv4 cidr mask"
});
/**
 * @since 1.0.0
 * @category Branded constructors
 */
export const IPv6CidrMaskBrand = /*#__PURE__*/Brand.nominal();
/**
 * An ipv6 cidr mask, which is a number between 0 and 128.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import {
 *         IPv6CidrMask,
 *         IPv6CidrMaskBrand,
 *     } from "the-wireguard-effect/InternetSchemas";
 *
 *     const mask: IPv6CidrMaskBrand = IPv6CidrMaskBrand(64);
 *     assert.strictEqual(mask, 64);
 *
 *     const decodeMask = Schema.decodeSync(IPv6CidrMask);
 *     assert.strictEqual(decodeMask(64), 64);
 *
 *     assert.throws(() => decodeMask(129));
 *     assert.doesNotThrow(() => decodeMask(0));
 *     assert.doesNotThrow(() => decodeMask(128));
 */
export const IPv6CidrMask = /*#__PURE__*/Schema.Int.pipe(Schema.between(0, 128)).pipe(Schema.fromBrand(IPv6CidrMaskBrand)).annotations({
  identifier: "IPv6CidrMask",
  description: "An ipv6 cidr mask"
});
/**
 * @since 1.0.0
 * @category Api interface
 */
export class CidrBlockBase extends /*#__PURE__*/Schema.Class("CidrBlockMixin")({
  address: Address,
  mask: /*#__PURE__*/Schema.Union(IPv4CidrMask, IPv6CidrMask)
}) {
  /** @since 1.0.0 */
  family = this.address.family;
  /** @internal */
  onFamily({
    onIPv4,
    onIPv6
  }) {
    const isIPv4 = () => this.family === "ipv4";
    const isIPv6 = () => this.family === "ipv6";
    if (isIPv4()) {
      return onIPv4(this);
    } else if (isIPv6()) {
      return onIPv6(this);
    } else {
      return Function.absurd(this.family);
    }
  }
  /**
   * The first address in the range given by this address' subnet, often
   * referred to as the Network Address.
   *
   * @since 1.0.0
   */
  get networkAddressAsBigint() {
    return Effect.gen(this, function* () {
      const bits = this.family === "ipv4" ? 32 : 128;
      const bigIntegerAddress = yield* this.onFamily({
        onIPv4: self => Schema.decode(IPv4Bigint)(self.address.ip),
        onIPv6: self => Schema.decode(IPv6Bigint)(self.address.ip)
      });
      const intermediate = bigIntegerAddress.value.toString(2).padStart(bits, "0").slice(0, this.mask);
      const networkAddressString = intermediate + "0".repeat(bits - this.mask);
      const networkAddressBigInt = BigInt(`0b${networkAddressString}`);
      return this.onFamily({
        onIPv4: _self => IPv4BigintBrand(networkAddressBigInt),
        onIPv6: _self => IPv6BigintBrand(networkAddressBigInt)
      });
    });
  }
  /**
   * The first address in the range given by this address' subnet, often
   * referred to as the Network Address.
   *
   * @since 1.0.0
   */
  networkAddress() {
    return this.onFamily({
      onIPv4: self => Function.pipe(self.networkAddressAsBigint, Effect.flatMap(value => Schema.encode(IPv4Bigint)({
        value,
        family: "ipv4"
      })), Effect.flatMap(Schema.decode(IPv4))),
      onIPv6: self => Function.pipe(self.networkAddressAsBigint, Effect.flatMap(value => Schema.encode(IPv6Bigint)({
        value,
        family: "ipv6"
      })), Effect.flatMap(Schema.decode(IPv6)))
    });
  }
  /**
   * The last address in the range given by this address' subnet, often
   * referred to as the Broadcast Address.
   *
   * @since 1.0.0
   */
  get broadcastAddressAsBigint() {
    return Effect.gen(this, function* () {
      const bits = this.family === "ipv4" ? 32 : 128;
      const bigIntegerAddress = yield* this.onFamily({
        onIPv4: self => Schema.decode(IPv4Bigint)(self.address.ip),
        onIPv6: self => Schema.decode(IPv6Bigint)(self.address.ip)
      });
      const intermediate = bigIntegerAddress.value.toString(2).padStart(bits, "0").slice(0, this.mask);
      const broadcastAddressString = intermediate + "1".repeat(bits - this.mask);
      const broadcastAddressBigInt = BigInt(`0b${broadcastAddressString}`);
      return this.onFamily({
        onIPv4: _self => IPv4BigintBrand(broadcastAddressBigInt),
        onIPv6: _self => IPv6BigintBrand(broadcastAddressBigInt)
      });
    });
  }
  /**
   * The last address in the range given by this address' subnet, often
   * referred to as the Broadcast Address.
   *
   * @since 1.0.0
   */
  broadcastAddress() {
    return this.onFamily({
      onIPv4: self => Function.pipe(self.broadcastAddressAsBigint, Effect.flatMap(value => Schema.encode(IPv4Bigint)({
        value,
        family: "ipv4"
      })), Effect.flatMap(Schema.decode(IPv4))),
      onIPv6: self => Function.pipe(self.broadcastAddressAsBigint, Effect.flatMap(value => Schema.encode(IPv6Bigint)({
        value,
        family: "ipv6"
      })), Effect.flatMap(Schema.decode(IPv6)))
    });
  }
  /**
   * A stream of all addresses in the range given by this address' subnet.
   *
   * @since 1.0.0
   */
  get range() {
    return this.onFamily({
      onIPv4: self => Effect.gen(function* () {
        const minValue = yield* self.networkAddressAsBigint;
        const maxValue = yield* self.broadcastAddressAsBigint;
        return Function.pipe(Stream.iterate(minValue, x => IPv4BigintBrand(x + 1n)), Stream.takeWhile(n => n <= maxValue), Stream.flatMap(value => Schema.encode(IPv4Bigint)({
          value,
          family: "ipv4"
        })), Stream.mapEffect(Schema.decode(IPv4)));
      }).pipe(Stream.unwrap),
      onIPv6: self => Effect.gen(function* () {
        const minValue = yield* self.networkAddressAsBigint;
        const maxValue = yield* self.broadcastAddressAsBigint;
        return Function.pipe(Stream.iterate(minValue, x => IPv6BigintBrand(x + 1n)), Stream.takeWhile(n => n <= maxValue), Stream.flatMap(value => Schema.encode(IPv6Bigint)({
          value,
          family: "ipv6"
        })), Stream.mapEffect(Schema.decode(IPv6)));
      }).pipe(Stream.unwrap)
    });
  }
  /**
   * The total number of addresses in the range given by this address' subnet.
   *
   * @since 1.0.0
   */
  get total() {
    return Effect.gen(this, function* () {
      const minValue = yield* this.networkAddressAsBigint;
      const maxValue = yield* this.broadcastAddressAsBigint;
      return maxValue - minValue + 1n;
    });
  }
  /**
   * Finds the smallest CIDR block that contains all the given IP addresses.
   *
   * @since 1.0.0
   */
  static cidrBlockForRange = inputs => Effect.gen(function* () {
    const bigIntMinAndMax = args => {
      return args.reduce(([min, max], e) => {
        return [e < min ? e : min, e > max ? e : max];
      }, [args[0], args[0]]);
    };
    const bigints = yield* Function.pipe(inputs, Array.map(address => address.family === "ipv4" ? Schema.decode(IPv4Bigint)(address.ip) : Schema.decode(IPv6Bigint)(address.ip)), Array.map(x => x), Array.map(Effect.map(({
      value
    }) => value)), Effect.all);
    const bits = inputs[0].family === "ipv4" ? 32 : 128;
    const [min, max] = bigIntMinAndMax(bigints);
    const leadingZerosInMin = bits - min.toString(2).length;
    const leadingZerosInMax = bits - max.toString(2).length;
    const cidrMask = Math.min(leadingZerosInMin, leadingZerosInMax);
    const cidrAddress = inputs[0].family === "ipv4" ? yield* Schema.encode(IPv4Bigint)({
      value: IPv4BigintBrand(min),
      family: "ipv4"
    }) : yield* Schema.encode(IPv6Bigint)({
      value: IPv6BigintBrand(min),
      family: "ipv6"
    });
    return yield* Schema.decode(CidrBlockFromString)(`${cidrAddress}/${cidrMask}`);
  });
}
/**
 * @since 1.0.0
 * @category Schemas
 */
export const IPv4CidrBlock = /*#__PURE__*/Schema.transformOrFail(Schema.Struct({
  address: IPv4,
  mask: IPv4CidrMask
}), CidrBlockBase, {
  encode: data => Effect.gen(function* () {
    const address = yield* Schema.decode(IPv4)(data.address);
    const mask = yield* Schema.decode(IPv4CidrMask)(data.mask);
    return {
      address,
      mask
    };
  }).pipe(Effect.mapError(({
    issue
  }) => issue)),
  decode: data => ParseResult.succeed({
    address: data.address.ip,
    mask: data.mask
  })
}).annotations({
  identifier: "IPv4CidrBlock",
  description: "An ipv4 cidr block"
});
/**
 * A schema that transforms a `string` into a `CidrBlock`.
 *
 * @since 1.0.0
 * @category Schemas
 */
export const IPv4CidrBlockFromString = /*#__PURE__*/Schema.transform(Schema.TemplateLiteral(Schema.String, Schema.Literal("/"), Schema.Number), IPv4CidrBlock, {
  decode: str => {
    const [address, mask] = splitLiteral(str, "/");
    return {
      address,
      mask: Number.parseInt(mask, 10)
    };
  },
  encode: ({
    address,
    mask
  }) => `${address}/${mask}`
}).annotations({
  identifier: "IPv4CidrBlockFromString",
  description: "An ipv4 cidr block from string"
});
/**
 * @since 1.0.0
 * @category Schemas
 */
export const IPv6CidrBlock = /*#__PURE__*/Schema.transformOrFail(Schema.Struct({
  address: IPv6,
  mask: IPv6CidrMask
}), CidrBlockBase, {
  encode: data => Effect.gen(function* () {
    const address = yield* Schema.decode(IPv6)(data.address);
    const mask = yield* Schema.decode(IPv6CidrMask)(data.mask);
    return {
      address,
      mask
    };
  }).pipe(Effect.mapError(({
    issue
  }) => issue)),
  decode: data => ParseResult.succeed({
    address: data.address.ip,
    mask: data.mask
  })
}).annotations({
  identifier: "IPv6CidrBlock",
  description: "An ipv6 cidr block"
});
/**
 * A schema that transforms a `string` into a `CidrBlock`.
 *
 * @since 1.0.0
 * @category Schemas
 */
export const IPv6CidrBlockFromString = /*#__PURE__*/Schema.transform(Schema.TemplateLiteral(Schema.String, Schema.Literal("/"), Schema.Number), IPv6CidrBlock, {
  decode: str => {
    const [address, mask] = splitLiteral(str, "/");
    return {
      address,
      mask: Number.parseInt(mask, 10)
    };
  },
  encode: ({
    address,
    mask
  }) => `${address}/${mask}`
}).annotations({
  identifier: "IPv6CidrBlockFromString",
  description: "An ipv6 cidr block from string"
});
/**
 * @since 1.0.0
 * @category Schemas
 */
export const CidrBlock = /*#__PURE__*/Schema.Union(IPv4CidrBlock, IPv6CidrBlock);
/**
 * A schema that transforms a `string` into a `CidrBlock`.
 *
 * @since 1.0.0
 * @category Schemas
 */
export const CidrBlockFromString = /*#__PURE__*/Schema.transform(Schema.TemplateLiteral(Schema.String, Schema.Literal("/"), Schema.Number), CidrBlock, {
  decode: str => {
    const [address, mask] = splitLiteral(str, "/");
    return {
      address,
      mask: Number.parseInt(mask, 10)
    };
  },
  encode: ({
    address,
    mask
  }) => `${address}/${mask}`
}).annotations({
  identifier: "CidrBlockFromString",
  description: "A cidr block"
});
/**
 * 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.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import { IPv4Endpoint } from "the-wireguard-effect/InternetSchemas";
 *
 *     const decodeEndpoint = Schema.decodeSync(IPv4Endpoint);
 *     const endpoint1 = decodeEndpoint("1.2.3.4:51820");
 *     const endpoint2 = decodeEndpoint("1.2.3.4:51820:41820");
 *
 *     const endpoint3 = decodeEndpoint({
 *         ip: "1.2.3.4",
 *         port: 51820,
 *         family: "ipv4",
 *     });
 *
 *     const endpoint4 = decodeEndpoint({
 *         ip: "1.2.3.4",
 *         natPort: 51820,
 *         listenPort: 41820,
 *         family: "ipv4",
 *     });
 */
export const IPv4Endpoint = /*#__PURE__*/Schema.transform(Schema.Union(Schema.Struct({
  ip: Schema.String,
  port: Schema.Number,
  family: IPv4Family
}), Schema.Struct({
  ip: Schema.String,
  natPort: Schema.Number,
  listenPort: Schema.Number,
  family: IPv4Family
}), Schema.TemplateLiteral(Schema.String, Schema.Literal(":"), Schema.Number), Schema.TemplateLiteral(Schema.String, Schema.Literal(":"), Schema.Number, Schema.Literal(":"), Schema.Number)), Schema.Struct({
  address: IPv4,
  natPort: Port,
  listenPort: Port
}), {
  decode: data => {
    const isObjectInput = !Predicate.isString(data);
    const [ip, natPort, listenPort] = isObjectInput ? [data.ip, "natPort" in data ? `${data.natPort}` : `${data.port}`, "listenPort" in data ? `${data.listenPort}` : undefined] : splitLiteral(data, ":");
    const natPortParsed = Number.parseInt(natPort, 10);
    const listenPortParsed = Predicate.isNotUndefined(listenPort) ? Number.parseInt(listenPort, 10) : natPortParsed;
    return {
      address: ip,
      natPort: natPortParsed,
      listenPort: listenPortParsed
    };
  },
  encode: ({
    address,
    listenPort,
    natPort
  }) => `${address}:${natPort}:${listenPort}`
}).annotations({
  identifier: "IPv4Endpoint",
  description: "An ipv4 wireguard endpoint"
});
/**
 * 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.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import { IPv6Endpoint } from "the-wireguard-effect/InternetSchemas";
 *
 *     const decodeEndpoint = Schema.decodeSync(IPv6Endpoint);
 *     const endpoint1 = decodeEndpoint(
 *         "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820"
 *     );
 *     const endpoint2 = decodeEndpoint(
 *         "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820:41820"
 *     );
 *
 *     const endpoint3 = decodeEndpoint({
 *         ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
 *         port: 51820,
 *         family: "ipv6",
 *     });
 *
 *     const endpoint4 = decodeEndpoint({
 *         ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
 *         natPort: 51820,
 *         listenPort: 41820,
 *         family: "ipv6",
 *     });
 */
export const IPv6Endpoint = /*#__PURE__*/Schema.transform(Schema.Union(Schema.Struct({
  ip: Schema.String,
  port: Schema.Number,
  family: IPv6Family
}), Schema.Struct({
  ip: Schema.String,
  natPort: Schema.Number,
  listenPort: Schema.Number,
  family: IPv6Family
}), Schema.TemplateLiteral(Schema.Literal("["), Schema.String, Schema.Literal("]"), Schema.Literal(":"), Schema.Number), Schema.TemplateLiteral(Schema.Literal("["), Schema.String, Schema.Literal("]"), Schema.Literal(":"), Schema.Number, Schema.Literal(":"), Schema.Number)), Schema.Struct({
  address: IPv6,
  natPort: Port,
  listenPort: Port
}), {
  decode: data => {
    const isObjectInput = !Predicate.isString(data);
    const [ip, natPort, listenPort] = isObjectInput ? [data.ip, "natPort" in data ? `${data.natPort}` : `${data.port}`, "listenPort" in data ? `${data.listenPort}` : undefined] : [splitLiteral(data, "]")[0].slice(1), ...tail(splitLiteral(splitLiteral(data, "]")[1], ":"))];
    const natPortParsed = Number.parseInt(natPort, 10);
    const listenPortParsed = Predicate.isNotUndefined(listenPort) ? Number.parseInt(listenPort, 10) : natPortParsed;
    return {
      address: ip.slice(1),
      natPort: natPortParsed,
      listenPort: listenPortParsed
    };
  },
  encode: ({
    address,
    listenPort,
    natPort
  }) => `[${address}]:${natPort}:${listenPort}`
}).annotations({
  identifier: "IPv6Endpoint",
  description: "An ipv6 wireguard endpoint"
});
/**
 * A hostname wireguard endpoint, which consists of a hostname 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.
 *
 * @since 1.0.0
 * @category Schemas
 */
export const HostnameEndpoint = /*#__PURE__*/Schema.transform(Schema.Union(Schema.Struct({
  host: Schema.String,
  port: Schema.Number
}), Schema.Struct({
  host: Schema.String,
  natPort: Schema.Number,
  listenPort: Schema.Number
}), Schema.TemplateLiteral(Schema.String, Schema.Literal(":"), Schema.Number), Schema.TemplateLiteral(Schema.String, Schema.Literal(":"), Schema.Number, Schema.Literal(":"), Schema.Number)), Schema.Struct({
  host: Schema.String,
  natPort: Port,
  listenPort: Port
}), {
  decode: data => {
    const isObjectInput = !Predicate.isString(data);
    const [host, natPort, listenPort] = isObjectInput ? [data.host, "natPort" in data ? `${data.natPort}` : `${data.port}`, "listenPort" in data ? `${data.listenPort}` : undefined] : splitLiteral(data, ":");
    const natPortParsed = Number.parseInt(natPort, 10);
    const listenPortParsed = Predicate.isNotUndefined(listenPort) ? Number.parseInt(listenPort, 10) : natPortParsed;
    return {
      host,
      natPort: natPortParsed,
      listenPort: listenPortParsed
    };
  },
  encode: ({
    host,
    listenPort,
    natPort
  }) => `${host}:${natPort}:${listenPort}`
}).annotations({
  identifier: "HostnameEndpoint",
  description: "A hostname endpoint"
});
/**
 * A wireguard endpoint, which is either an IPv4 or IPv6 endpoint.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *
 *     import { Endpoint } from "the-wireguard-effect/InternetSchemas";
 *
 *     const decodeEndpoint = Schema.decodeSync(Endpoint);
 *     const endpoint1 = decodeEndpoint("1.2.3.4:51820");
 *     const endpoint2 = decodeEndpoint("1.2.3.4:51820:41820");
 *
 *     const endpoint3 = decodeEndpoint({
 *         ip: "1.2.3.4",
 *         port: 51820,
 *         family: "ipv4",
 *     });
 *
 *     const endpoint4: Endpoint = decodeEndpoint({
 *         ip: "1.2.3.4",
 *         natPort: 51820,
 *         listenPort: 41820,
 *         family: "ipv4",
 *     });
 *
 *     const endpoint5 = decodeEndpoint(
 *         "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820"
 *     );
 *     const endpoint6 = decodeEndpoint(
 *         "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820:41820"
 *     );
 *
 *     const endpoint7 = decodeEndpoint({
 *         ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
 *         port: 51820,
 *         family: "ipv6",
 *     });
 *
 *     const endpoint8: Endpoint = decodeEndpoint({
 *         ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
 *         natPort: 51820,
 *         listenPort: 41820,
 *         family: "ipv6",
 *     });
 *
 * @see {@link IPv4Endpoint}
 * @see {@link IPv6Endpoint}
 * @see {@link HostnameEndpoint}
 */
export const Endpoint = /*#__PURE__*/Schema.Union(IPv4Endpoint, IPv6Endpoint, HostnameEndpoint).annotations({
  identifier: "Endpoint",
  description: "An ipv4, ipv6, or hostname wireguard endpoint"
});
/**
 * A wireguard setup data, which consists of an endpoint followed by an address.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import { SetupData } from "the-wireguard-effect/InternetSchemas";
 *
 *     const decodeSetupData = Schema.decodeSync(SetupData);
 *     const setupData = decodeSetupData(["1.1.1.1:51280", "10.0.0.1"]);
 *
 * @see {@link IPv4}
 * @see {@link IPv4EndpointSchema}
 */
export const IPv4SetupData = /*#__PURE__*/Schema.Tuple(IPv4Endpoint, IPv4).annotations({
  identifier: "SetupData",
  description: "A wireguard setup data"
});
/**
 * A wireguard setup data, which consists of an endpoint followed by an address.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import { SetupData } from "the-wireguard-effect/InternetSchemas";
 *
 *     const decodeSetupData = Schema.decodeSync(SetupData);
 *     const setupData = decodeSetupData(["1.1.1.1:51280", "10.0.0.1"]);
 *
 * @see {@link IPv6}
 * @see {@link IPv6EndpointSchema}
 */
export const IPv6SetupData = /*#__PURE__*/Schema.Tuple(IPv6Endpoint, IPv6).annotations({
  identifier: "SetupData",
  description: "A wireguard setup data"
});
/**
 * A wireguard setup data, which consists of an endpoint followed by an address.
 *
 * @since 1.0.0
 * @category Schemas
 * @see {@link IPv4}
 * @see {@link HostnameEndpoint}
 */
export const HostnameIPv4SetupData = /*#__PURE__*/Schema.Tuple(HostnameEndpoint, IPv4).annotations({
  identifier: "HostnameIPv4SetupData",
  description: "A wireguard hostname+ipv4 setup data"
});
/**
 * A wireguard setup data, which consists of an endpoint followed by an address.
 *
 * @since 1.0.0
 * @category Schemas
 * @see {@link IPv6}
 * @see {@link HostnameEndpoint}
 */
export const HostnameIPv6SetupData = /*#__PURE__*/Schema.Tuple(HostnameEndpoint, IPv6).annotations({
  identifier: "HostnameIPv6SetupData",
  description: "A wireguard hostname+ipv6 setup data"
});
/**
 * A wireguard setup data, which consists of an endpoint followed by an address.
 *
 * @since 1.0.0
 * @category Schemas
 * @example
 *     import * as Schema from "effect/Schema";
 *     import { SetupData } from "the-wireguard-effect/InternetSchemas";
 *
 *     const decodeSetupData = Schema.decodeSync(SetupData);
 *     const setupData = decodeSetupData(["1.1.1.1:51280", "10.0.0.1"]);
 *
 * @see {@link Address}
 * @see {@link Endpoint}
 */
export const SetupData = /*#__PURE__*/Schema.Union(IPv4SetupData, IPv6SetupData, HostnameIPv4SetupData, HostnameIPv6SetupData).annotations({
  identifier: "SetupData",
  description: "A wireguard setup data"
});
//# sourceMappingURL=InternetSchemas.js.map