import { useRef, useMemo, isValidElement, createElement, Fragment, lazy, Suspense } from "react";
import { useEnvironment, EnvironmentContext } from "@contember/binding";
import { Message, ContainerSpinner } from "@contember/ui";
import { MiscPageLayout } from "../MiscPageLayout.js";
import { PageErrorBoundary } from "./PageErrorBoundary.js";
import { useCurrentRequest } from "../../routing/RequestContext.js";
function findPrefix(strings) {
  if (strings.length === 0) {
    return "";
  }
  const sorted = [...strings].sort();
  const a = sorted[0];
  const b = sorted[sorted.length - 1];
  let i = 0;
  let j = 0;
  while (j < a.length && a.charAt(j) === b.charAt(j)) {
    j++;
    if (a.charAt(j) === "/") {
      i = j + 1;
    }
  }
  return a.substring(0, i);
}
function disallowAction(Component) {
  return (props) => {
    const pageName = useCurrentRequest()?.pageName;
    if (props.action !== void 0) {
      throw new Error(`No such page as ${pageName}.`);
    }
    return /* @__PURE__ */ createElement(Component, null);
  };
}
const Pages = ({ children, layout }) => {
  const rootEnv = useEnvironment();
  const request = useCurrentRequest();
  const requestId = useRef(0);
  const Layout = layout ?? Fragment;
  const pageMap = useMemo(() => {
    if (Array.isArray(children)) {
      if (children.every((child) => isPageProviderElement(child))) {
        return new Map(children.map((child) => [child.type.getPageName(child.props), disallowAction(() => child)]));
      } else {
        throw new Error("Pages has a child which is not a Page");
      }
    } else if (isPageProviderElement(children)) {
      return /* @__PURE__ */ new Map([[children.type.getPageName(children.props), disallowAction(() => children)]]);
    } else {
      const modules = Object.entries(children).filter(([k, v]) => isLazyPageModule(k, v) || isEagerPageModule(k, v));
      const modulesPrefix = findPrefix(modules.map((it) => it[0]));
      const getPageNameFromFile = (name) => name.slice(modulesPrefix.length, -4);
      return new Map(Object.entries(children).flatMap(([k, v]) => {
        if (isLazyPageModule(k, v)) {
          const pageName = getPageNameFromFile(k);
          const PageActionHandler = (props) => {
            const Lazy = lazy(async () => {
              const module = normalizeModule(await v());
              const page = module[props.action ?? "default"];
              if (page === void 0) {
                throw new Error(`No such page as ${pageName}${props.action ? "/" + props.action : ""}.`);
              }
              return { default: isValidElement(page) ? () => page : page };
            });
            return /* @__PURE__ */ createElement(Suspense, {
              fallback: /* @__PURE__ */ createElement(ContainerSpinner, null)
            }, /* @__PURE__ */ createElement(Lazy, null));
          };
          return [[pageName, PageActionHandler]];
        } else if (isEagerPageModule(k, v)) {
          const pageName = getPageNameFromFile(k);
          const module = normalizeModule(v);
          const PageActionHandler = (props) => {
            const Page2 = module[props.action ?? "default"];
            if (Page2 === void 0) {
              throw new Error(`No such page as ${pageName}${props.action ? "/" + props.action : ""}.`);
            }
            return isValidElement(Page2) ? Page2 : /* @__PURE__ */ createElement(Page2, null);
          };
          return [[pageName, PageActionHandler]];
        } else {
          const pageName = lowerFirst(k);
          if (isPageProviderElement(v)) {
            return [[v.type.getPageName(v.props, pageName), disallowAction(() => v)]];
          } else if (isValidElement(v)) {
            return [[pageName, disallowAction(() => v)]];
          } else {
            return [[pageName, disallowAction(v)]];
          }
        }
      }));
    }
  }, [children]);
  if (request === null) {
    return /* @__PURE__ */ createElement(MiscPageLayout, null, /* @__PURE__ */ createElement(Message, {
      intent: "danger",
      size: "large"
    }, "Page not found"));
  }
  let pageKey = request.pageName;
  let pageAction = void 0;
  let Page = pageMap.get(pageKey);
  if (Page === void 0) {
    const pos = request.pageName.lastIndexOf("/");
    if (pos > 0) {
      pageKey = request.pageName.slice(0, pos);
      pageAction = request.pageName.slice(pos + 1);
      Page = pageMap.get(pageKey);
    }
  }
  if (Page === void 0) {
    throw new Error(`No such page as ${request.pageName}.`);
  }
  const requestEnv = rootEnv.withDimensions(request.dimensions).withParameters(request.parameters);
  return /* @__PURE__ */ createElement(EnvironmentContext.Provider, {
    value: requestEnv
  }, /* @__PURE__ */ createElement(Layout, null, /* @__PURE__ */ createElement(PageErrorBoundary, {
    key: requestId.current++
  }, /* @__PURE__ */ createElement(Page, {
    action: pageAction
  }))));
};
function isPageProvider(it) {
  return typeof it.getPageName === "function";
}
function isPageProviderElement(el) {
  return isValidElement(el) && typeof el.type !== "string" && isPageProvider(el.type);
}
function isLazyPageModule(name, it) {
  return (name.endsWith(".tsx") || name.endsWith(".jsx")) && typeof it === "function";
}
function isEagerPageModule(name, it) {
  return (name.endsWith(".tsx") || name.endsWith(".jsx")) && typeof it === "object";
}
function lowerFirst(val) {
  return val.slice(0, 1).toLowerCase() + val.slice(1);
}
function normalizeModule(map) {
  return Object.fromEntries(Object.entries(map).map(([k, v]) => [lowerFirst(k), v]));
}
export { Pages };
//# sourceMappingURL=Pages.js.map
