"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.within = exports.upperCase = exports.unnested = exports.snakeCase = exports.orElse = exports.nested = exports.makeFlat = exports.make = exports.lowerCase = exports.kebabCase = exports.fromMap = exports.fromFlat = exports.fromEnv = exports.contramapPath = exports.constantCase = exports.configProviderTag = exports.FlatConfigProviderTypeId = exports.ConfigProviderTypeId = void 0;
var Context = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Context"));
var Debug = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Debug"));
var Either = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Either"));
var HashMap = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/HashMap"));
var HashSet = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/HashSet"));
var number = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Number"));
var Option = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/Option"));
var RA = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/data/ReadonlyArray"));
var _config = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal_effect_untraced/config"));
var configError = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal_effect_untraced/configError"));
var pathPatch = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal_effect_untraced/configProvider/pathPatch"));
var core = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal_effect_untraced/core"));
var OpCodes = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal_effect_untraced/opCodes/config"));
var StringUtils = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/io/internal_effect_untraced/string-utils"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const concat = (l, r) => [...l, ...r];
/** @internal */
const ConfigProviderSymbolKey = "@effect/io/Config/Provider";
/** @internal */
const ConfigProviderTypeId = /*#__PURE__*/Symbol.for(ConfigProviderSymbolKey);
/** @internal */
exports.ConfigProviderTypeId = ConfigProviderTypeId;
const configProviderTag = /*#__PURE__*/Context.Tag(ConfigProviderTypeId);
/** @internal */
exports.configProviderTag = configProviderTag;
const FlatConfigProviderSymbolKey = "@effect/io/Config/Provider/Flat";
/** @internal */
const FlatConfigProviderTypeId = /*#__PURE__*/Symbol.for(FlatConfigProviderSymbolKey);
/** @internal */
exports.FlatConfigProviderTypeId = FlatConfigProviderTypeId;
const make = /*#__PURE__*/Debug.untracedMethod(restore => (load, flattened) => ({
  [ConfigProviderTypeId]: ConfigProviderTypeId,
  load: Debug.methodWithTrace(trace => config => restore(load)(config).traced(trace)),
  flattened
}));
/** @internal */
exports.make = make;
const makeFlat = /*#__PURE__*/Debug.untracedMethod(restore => (load, enumerateChildren, patch) => ({
  [FlatConfigProviderTypeId]: FlatConfigProviderTypeId,
  patch,
  load: Debug.methodWithTrace(trace => (path, config, split = true) => restore(load)(path, config, split).traced(trace)),
  enumerateChildren: Debug.methodWithTrace(trace => path => restore(enumerateChildren)(path).traced(trace))
}));
/** @internal */
exports.makeFlat = makeFlat;
const fromFlat = /*#__PURE__*/Debug.untracedMethod(() => flat => make(config => core.flatMap(fromFlatLoop(flat, RA.empty(), config, false), chunk => Option.match(() => core.fail(configError.MissingData(RA.empty(), `Expected a single value having structure: ${config}`)), core.succeed)(RA.head(chunk))), flat));
/** @internal */
exports.fromFlat = fromFlat;
const fromEnv = /*#__PURE__*/Debug.untracedMethod(() => (config = {}) => {
  const {
    pathDelim,
    seqDelim
  } = Object.assign({}, {
    pathDelim: "_",
    seqDelim: ","
  }, config);
  const makePathString = path => RA.join(pathDelim)(path);
  const unmakePathString = pathString => pathString.split(pathDelim);
  const getEnv = () => typeof process !== "undefined" && "env" in process && typeof process.env === "object" ? process.env : {};
  const load = (path, primitive, split = true) => {
    const pathString = makePathString(path);
    const current = getEnv();
    const valueOpt = pathString in current ? Option.some(current[pathString]) : Option.none();
    return core.flatMap(value => parsePrimitive(value, path, primitive, seqDelim, split))(core.mapError(() => configError.MissingData(path, `Expected ${pathString} to exist in the process context`))(valueOpt));
  };
  const enumerateChildren = path => core.sync(() => {
    const current = getEnv();
    const keys = Object.keys(current);
    const keyPaths = Array.from(keys).map(value => unmakePathString(value.toUpperCase()));
    const filteredKeyPaths = keyPaths.filter(keyPath => {
      for (let i = 0; i < path.length; i++) {
        const pathComponent = RA.unsafeGet(i)(path);
        const currentElement = keyPath[i];
        if (currentElement === undefined || pathComponent !== currentElement) {
          return false;
        }
      }
      return true;
    }).flatMap(keyPath => keyPath.slice(path.length, path.length + 1));
    return HashSet.fromIterable(filteredKeyPaths);
  });
  return fromFlat(makeFlat(load, enumerateChildren, pathPatch.empty));
});
/** @internal */
exports.fromEnv = fromEnv;
const fromMap = /*#__PURE__*/Debug.untracedMethod(() => (map, config = {}) => {
  const {
    pathDelim,
    seqDelim
  } = Object.assign({}, {
    seqDelim: ",",
    pathDelim: "."
  }, config);
  const makePathString = path => RA.join(pathDelim)(path);
  const unmakePathString = pathString => pathString.split(pathDelim);
  const mapWithIndexSplit = splitIndexInKeys(map, str => Array.from(unmakePathString(str)), makePathString);
  const load = (path, primitive, split = true) => {
    const pathString = makePathString(path);
    const valueOpt = mapWithIndexSplit.has(pathString) ? Option.some(mapWithIndexSplit.get(pathString)) : Option.none();
    return core.flatMap(value => parsePrimitive(value, path, primitive, seqDelim, split))(core.mapError(() => configError.MissingData(path, `Expected ${pathString} to exist in the provided map`))(valueOpt));
  };
  const enumerateChildren = path => core.sync(() => {
    const keyPaths = Array.from(mapWithIndexSplit.keys()).map(unmakePathString);
    const filteredKeyPaths = keyPaths.filter(keyPath => {
      for (let i = 0; i < path.length; i++) {
        const pathComponent = RA.unsafeGet(i)(path);
        const currentElement = keyPath[i];
        if (currentElement === undefined || pathComponent !== currentElement) {
          return false;
        }
      }
      return true;
    }).flatMap(keyPath => keyPath.slice(path.length, path.length + 1));
    return HashSet.fromIterable(filteredKeyPaths);
  });
  return fromFlat(makeFlat(load, enumerateChildren, pathPatch.empty));
});
exports.fromMap = fromMap;
const extend = (leftDef, rightDef, left, right) => {
  const leftPad = RA.unfold(left.length, index => index >= right.length ? Option.none() : Option.some([leftDef(index), index + 1]));
  const rightPad = RA.unfold(right.length, index => index >= left.length ? Option.none() : Option.some([rightDef(index), index + 1]));
  const leftExtension = concat(left, leftPad);
  const rightExtension = concat(right, rightPad);
  return [leftExtension, rightExtension];
};
const fromFlatLoop = (flat, prefix, config, split) => {
  const op = config;
  switch (op._tag) {
    case OpCodes.OP_CONSTANT:
      {
        return core.succeed(RA.of(op.value));
      }
    case OpCodes.OP_DESCRIBED:
      {
        return core.suspend(() => fromFlatLoop(flat, prefix, op.config, split));
      }
    case OpCodes.OP_FAIL:
      {
        return core.fail(configError.MissingData(prefix, op.message));
      }
    case OpCodes.OP_FALLBACK:
      {
        return core.catchAll(error1 => {
          if (op.condition(error1)) {
            return core.catchAll(error2 => core.fail(configError.Or(error1, error2)))(fromFlatLoop(flat, prefix, op.second, split));
          }
          return core.fail(error1);
        })(core.suspend(() => fromFlatLoop(flat, prefix, op.first, split)));
      }
    case OpCodes.OP_LAZY:
      {
        return core.suspend(() => fromFlatLoop(flat, prefix, op.config(), split));
      }
    case OpCodes.OP_MAP_OR_FAIL:
      {
        return core.suspend(() => core.flatMap(core.forEach(a => core.mapError(configError.prefixed(prefix))(op.mapOrFail(a))))(fromFlatLoop(flat, prefix, op.original, split)));
      }
    case OpCodes.OP_NESTED:
      {
        return core.suspend(() => fromFlatLoop(flat, concat(prefix, RA.of(op.name)), op.config, split));
      }
    case OpCodes.OP_PRIMITIVE:
      {
        return core.flatMap(prefix => core.flatMap(values => {
          if (values.length === 0) {
            const name = Option.getOrElse(() => "<n/a>")(RA.last(prefix));
            return core.fail(_config.missingError(name));
          }
          return core.succeed(values);
        })(flat.load(prefix, op, split)))(pathPatch.patch(prefix, flat.patch));
      }
    case OpCodes.OP_SEQUENCE:
      {
        return core.flatMap(patchedPrefix => core.flatMap(indices => {
          if (indices.length === 0) {
            return core.suspend(() => core.map(fromFlatLoop(flat, patchedPrefix, op.config, true), RA.of));
          }
          return core.map(chunkChunk => {
            const flattened = RA.flatten(chunkChunk);
            if (flattened.length === 0) {
              return RA.of(RA.empty());
            }
            return RA.of(flattened);
          })(core.forEach(indices, index => fromFlatLoop(flat, RA.append(prefix, `[${index}]`), op.config, true)));
        })(core.flatMap(indicesFrom)(flat.enumerateChildren(patchedPrefix))))(pathPatch.patch(prefix, flat.patch));
      }
    case OpCodes.OP_TABLE:
      {
        return core.suspend(() => core.flatMap(prefix => core.flatMap(keys => {
          return core.map(values => {
            if (values.length === 0) {
              return RA.of(HashMap.empty());
            }
            const matrix = values.map(x => Array.from(x));
            return RA.map(values => HashMap.fromIterable(RA.zip(RA.fromIterable(keys), values)))(transpose(matrix));
          })(core.forEach(key => fromFlatLoop(flat, concat(prefix, RA.of(key)), op.valueConfig, split))(keys));
        })(flat.enumerateChildren(prefix)))(pathPatch.patch(prefix, flat.patch)));
      }
    case OpCodes.OP_ZIP_WITH:
      {
        return core.suspend(() => core.flatMap(left => core.flatMap(right => {
          if (Either.isLeft(left) && Either.isLeft(right)) {
            return core.fail(configError.And(left.left, right.left));
          }
          if (Either.isLeft(left) && Either.isRight(right)) {
            return core.fail(left.left);
          }
          if (Either.isRight(left) && Either.isLeft(right)) {
            return core.fail(right.left);
          }
          if (Either.isRight(left) && Either.isRight(right)) {
            const path = RA.join(".")(prefix);
            const fail = fromFlatLoopFail(prefix, path);
            const [lefts, rights] = extend(fail, fail, RA.map(Either.right)(left.right), RA.map(Either.right)(right.right));
            return core.forEach(([left, right]) => core.map(([left, right]) => op.zip(left, right))(core.zip(left, right)))(RA.zip(rights)(lefts));
          }
          throw new Error("BUG: ConfigProvider.fromFlatLoop - please report an issue at https://github.com/Effect-TS/io/issues");
        })(core.either(fromFlatLoop(flat, prefix, op.right, split))))(core.either(fromFlatLoop(flat, prefix, op.left, split))));
      }
  }
};
const fromFlatLoopFail = (prefix, path) => index => Either.left(configError.MissingData(prefix, `The element at index ${index} in a sequence at path "${path}" was missing`));
/** @internal */
const contramapPath = /*#__PURE__*/Debug.untracedDual(2, restore => (self, f) => fromFlat(contramapPathFlat(self.flattened, restore(f))));
exports.contramapPath = contramapPath;
const contramapPathFlat = (self, f) => makeFlat((path, config, split = true) => self.load(path, config, split), path => self.enumerateChildren(path), pathPatch.mapName(self.patch, f));
/** @internal */
const nested = /*#__PURE__*/Debug.untracedDual(2, () => (self, name) => fromFlat(makeFlat((path, config) => self.flattened.load(path, config, true), path => self.flattened.enumerateChildren(path), pathPatch.nested(self.flattened.patch, name))));
/** @internal */
exports.nested = nested;
const unnested = /*#__PURE__*/Debug.untracedDual(2, () => (self, name) => fromFlat(makeFlat((path, config) => self.flattened.load(path, config, true), path => self.flattened.enumerateChildren(path), pathPatch.unnested(self.flattened.patch, name))));
/** @internal */
exports.unnested = unnested;
const orElse = /*#__PURE__*/Debug.untracedDual(2, restore => (self, that) => fromFlat(orElseFlat(self.flattened, () => restore(that)().flattened)));
exports.orElse = orElse;
const orElseFlat = (self, that) => makeFlat((path, config, split) => core.catchAll(error1 => core.flatMap(that => core.catchAll(error2 => core.fail(configError.Or(error1, error2)))(core.flatMap(patch => that.load(patch, config, split))(pathPatch.patch(path, that.patch))))(core.sync(that)))(core.flatMap(patch => self.load(patch, config, split))(pathPatch.patch(path, self.patch))), path => core.flatMap(left => core.flatMap(that => core.flatMap(right => {
  if (Either.isLeft(left) && Either.isLeft(right)) {
    return core.fail(configError.And(left.left, right.left));
  }
  if (Either.isLeft(left) && Either.isRight(right)) {
    return core.succeed(right.right);
  }
  if (Either.isRight(left) && Either.isLeft(right)) {
    return core.succeed(left.right);
  }
  if (Either.isRight(left) && Either.isRight(right)) {
    return core.succeed(HashSet.union(right.right)(left.right));
  }
  throw new Error("BUG: ConfigProvider.orElseFlat - please report an issue at https://github.com/Effect-TS/io/issues");
})(core.either(core.flatMap(patch => that.enumerateChildren(patch))(pathPatch.patch(path, that.patch)))))(core.sync(that)))(core.either(core.flatMap(patch => self.enumerateChildren(patch))(pathPatch.patch(path, self.patch)))), pathPatch.empty);
/** @internal */
const constantCase = self => contramapPath(self, StringUtils.constantCase);
/** @internal */
exports.constantCase = constantCase;
const kebabCase = self => contramapPath(self, StringUtils.kebabCase);
/** @internal */
exports.kebabCase = kebabCase;
const lowerCase = self => contramapPath(self, StringUtils.lowerCase);
/** @internal */
exports.lowerCase = lowerCase;
const snakeCase = self => contramapPath(self, StringUtils.snakeCase);
/** @internal */
exports.snakeCase = snakeCase;
const upperCase = self => contramapPath(self, StringUtils.upperCase);
/** @internal */
exports.upperCase = upperCase;
const within = /*#__PURE__*/Debug.untracedDual(3, () => (self, path, f) => {
  const unnest = RA.reduce(path, self, (provider, name) => unnested(provider, name));
  const nest = RA.reduceRight(path, f(unnest), (provider, name) => nested(provider, name));
  return orElse(nest, () => self);
});
exports.within = within;
const splitPathString = (text, delim) => {
  const split = text.split(new RegExp(`\\s*${escapeRegex(delim)}\\s*`));
  return split;
};
const parsePrimitive = (text, path, primitive, delimiter, split) => {
  if (!split) {
    return core.mapError(configError.prefixed(path))(core.map(RA.of)(primitive.parse(text)));
  }
  return core.mapError(configError.prefixed(path))(core.forEach(char => primitive.parse(char.trim()))(splitPathString(text, delimiter)));
};
const transpose = array => {
  return Object.keys(array[0]).map(column => array.map(row => row[column]));
};
const escapeRegex = string => {
  return string.replace(/[/\-\\^$*+?.()|[\]{}]/g, "\\$&");
};
const indicesFrom = quotedIndices => core.map(Either.merge)(core.either(core.mapBoth(() => RA.empty(), RA.sort(number.Order))(core.forEach(quotedIndices, parseQuotedIndex))));
const STR_INDEX_REGEX = /(^.+)(\[(\d+)\])$/;
const QUOTED_INDEX_REGEX = /^(\[(\d+)\])$/;
const parseQuotedIndex = str => {
  const match = str.match(QUOTED_INDEX_REGEX);
  if (match !== null) {
    const matchedIndex = match[2];
    return Option.flatMap(parseInteger)(matchedIndex !== undefined && matchedIndex.length > 0 ? Option.some(matchedIndex) : Option.none());
  }
  return Option.none();
};
const splitIndexInKeys = (map, unmakePathString, makePathString) => {
  const newMap = new Map();
  for (const [pathString, value] of map) {
    const keyWithIndex = RA.flatMap(key => Option.match(splitIndexFrom(key), () => RA.of(key), ([key, index]) => RA.make(key, `[${index}]`)))(unmakePathString(pathString));
    newMap.set(makePathString(keyWithIndex), value);
  }
  return newMap;
};
const splitIndexFrom = key => {
  const match = key.match(STR_INDEX_REGEX);
  if (match !== null) {
    const matchedString = match[1];
    const matchedIndex = match[3];
    const optionalString = matchedString !== undefined && matchedString.length > 0 ? Option.some(matchedString) : Option.none();
    const optionalIndex = Option.flatMap(parseInteger)(matchedIndex !== undefined && matchedIndex.length > 0 ? Option.some(matchedIndex) : Option.none());
    return Option.tuple(optionalString, optionalIndex);
  }
  return Option.none();
};
const parseInteger = str => {
  const parsedIndex = Number.parseInt(str);
  return Number.isNaN(parsedIndex) ? Option.none() : Option.some(parsedIndex);
};
//# sourceMappingURL=configProvider.js.map