import * as pathToRegexp from "path-to-regexp";
const matchFunctionsCache = {};
const pathFunctionsCache = {};
const dimensionsIn = (dimensions) => {
  return dimensions.split("+").map((pair) => pair.split("=")).reduce((acc, [key, value]) => ({ ...acc, [key]: value.split(",") }), {});
};
const dimensionsOut = (dimensions) => {
  return Object.entries(dimensions).map(([key, value]) => `${key}=${value.join(",")}`).join("+");
};
const pageNameIn = (pageName) => {
  return pageName.replace(/-([a-z])/g, (m) => m[1].toUpperCase());
};
const pageNameOut = (pageName) => {
  return pageName.replace(/([A-Z])/g, "-$1").toLowerCase();
};
const pathToRequestState = (routing, path, query) => {
  var _a;
  if (!path.startsWith(routing.basePath.slice(0, -1))) {
    return null;
  }
  const dimensionsSegment = path.slice(routing.basePath.length, path.indexOf("/", routing.basePath.length));
  const hasDimensions = dimensionsSegment.includes("=");
  const dimensions = hasDimensions ? dimensionsIn(dimensionsSegment) : routing.defaultDimensions;
  const pagePath = hasDimensions ? path.slice(routing.basePath.length + dimensionsSegment.length) : path.slice(routing.basePath.length - 1);
  const pagePathNormalized = pagePath.endsWith("/") ? pagePath : `${pagePath}/`;
  for (const [pageName2, config] of Object.entries(routing.routes)) {
    matchFunctionsCache[_a = config.path] ?? (matchFunctionsCache[_a] = pathToRegexp.match(config.path, { decode: decodeURIComponent }));
    const matchResult = matchFunctionsCache[config.path](pagePathNormalized);
    if (matchResult !== false) {
      return {
        pageName: pageName2,
        parameters: config.paramsToObject ? config.paramsToObject(matchResult.params) : matchResult.params,
        dimensions: dimensions ?? {}
      };
    }
  }
  const searchParams = new URLSearchParams(query);
  let pageName = pageNameIn(pagePathNormalized.slice(1, -1));
  if (routing.pageInQuery) {
    pageName = searchParams.get("page") || "index";
    searchParams.delete("page");
  }
  return {
    pageName,
    parameters: Object.fromEntries(Array.from(searchParams, ([key, val]) => [key, parseInt(val, 10).toString() === val ? parseInt(val, 10) : val])),
    dimensions: dimensions ?? {}
  };
};
const requestStateToPath = (routing, request) => {
  var _a;
  if (request === null) {
    throw new PageNotFound(`Unable to generate URL for empty request`);
  }
  const dimensionsString = dimensionsOut(request.dimensions);
  const dimensionsSegment = dimensionsString ? `/${dimensionsString}` : "";
  const prefix = routing.basePath.slice(0, -1) + dimensionsSegment;
  if (!routing.routes[request.pageName]) {
    const pageSegment2 = routing.pageInQuery ? "" : "/" + pageNameOut(request.pageName);
    const query = new URLSearchParams(request.parameters);
    if (routing.pageInQuery && request.pageName !== "index") {
      query.append("page", request.pageName);
    }
    const queryString = query.toString();
    const querySegment = queryString ? `?${queryString}` : "";
    return prefix + pageSegment2 + querySegment || "/";
  }
  const route = routing.routes[request.pageName];
  const pathParameters = route.objectToParams ? route.objectToParams(request.parameters) : request.parameters;
  pathFunctionsCache[_a = route.path] ?? (pathFunctionsCache[_a] = pathToRegexp.compile(route.path, { encode: encodeURIComponent }));
  const pageSegment = pathFunctionsCache[route.path](pathParameters);
  return prefix + pageSegment;
};
class PageNotFound extends Error {
  constructor(reason) {
    super("Page not found" + (reason && ": " + reason));
  }
}
export { PageNotFound, dimensionsIn, dimensionsOut, pageNameIn, pageNameOut, pathToRequestState, requestStateToPath };
//# sourceMappingURL=urlMapper.js.map
