import Boom from '@hapi/boom';
import { isEqual } from 'date-fns';
import { PREVIEW_PATH_PREFIX } from "../../../constants.js";
import { assertFormAvailable } from "../form-availability.js";
import { checkEmailAddressForLiveFormSubmission, getCacheService } from "../helpers.js";
import { FormModel } from "../models/index.js";
import { TerminalPageController } from "../pageControllers/index.js";
import * as defaultServices from "../services/index.js";
import { FormStatus } from "../../../routes/types.js";
export async function getFormModel(slug, state, options = {}) {
  const services = options.services ?? defaultServices;
  const {
    formsService
  } = services;
  const isPreview = isPreviewState(state, options);
  const formState = resolveState(state);
  const metadata = await formsService.getFormMetadata(slug);
  assertFormAvailable(metadata);
  const definition = await formsService.getFormDefinition(metadata.id, formState);
  if (!definition) {
    throw Boom.notFound(`No definition found for form metadata ${metadata.id} (${slug}) ${state}`);
  }
  return new FormModel(definition, {
    basePath: options.basePath ?? buildBasePath(options.routePrefix ?? '', slug, formState, isPreview),
    ordnanceSurveyApiKey: options.ordnanceSurveyApiKey,
    formId: options.formId ?? metadata.id
  }, services, options.controllers);
}
export async function getFormContext({
  server,
  yar
}, slug, state = FormStatus.Live, options = {}) {
  const formModel = await resolveFormModel(server, slug, state, options);
  const cacheService = getCacheService(server);
  const summaryRequest = {
    app: {},
    method: 'get',
    params: {
      path: 'summary',
      slug,
      ...(isPreviewState(state, options) && {
        state: resolveState(state)
      })
    },
    path: `/${formModel.basePath}/summary`,
    query: {},
    url: new URL(`/${formModel.basePath}/summary`, 'https://form-context.local'),
    server,
    yar
  };
  const cachedState = await cacheService.getState(summaryRequest);
  const formState = {
    ...cachedState,
    $$__referenceNumber: cachedState.$$__referenceNumber
  };
  return formModel.getFormContext(summaryRequest, formState, options.errors ?? []);
}
export async function resolveFormModel(server, slug, state, options = {}) {
  const services = options.services ?? defaultServices;
  const {
    formsService
  } = services;
  const metadata = await formsService.getFormMetadata(slug);
  assertFormAvailable(metadata);
  const formState = resolveState(state);
  const isPreview = options.isPreview ?? isPreviewState(state, options);
  const stateMetadata = metadata[formState];
  if (!stateMetadata) {
    throw Boom.notFound(`No '${formState}' state for form metadata ${metadata.id}`);
  }

  // The models cache is created lazily per server instance

  server.app.models ??= new Map();
  const cache = server.app.models;
  const cacheKey = `${metadata.id}_${formState}_${isPreview}`;
  let entry = cache.get(cacheKey);
  if (!entry || !isEqual(entry.updatedAt, stateMetadata.updatedAt)) {
    const definition = await formsService.getFormDefinition(metadata.id, formState);
    if (!definition) {
      throw Boom.notFound(`No definition found for form metadata ${metadata.id} (${slug}) ${state}`);
    }
    checkEmailAddressForLiveFormSubmission(metadata.notificationEmail, isPreview);
    const routePrefix = options.routePrefix ?? server.realm.modifiers.route.prefix;
    const model = new FormModel(definition, {
      basePath: options.basePath ?? buildBasePath(routePrefix, slug, formState, isPreview),
      ordnanceSurveyApiKey: options.ordnanceSurveyApiKey,
      formId: options.formId ?? metadata.id
    }, services, options.controllers);
    entry = {
      model,
      updatedAt: stateMetadata.updatedAt
    };
    cache.set(cacheKey, entry);
  }
  return entry.model;
}
function buildBasePath(routePrefix, slug, state, isPreview) {
  const base = (isPreview ? `${routePrefix}${PREVIEW_PATH_PREFIX}/${state}/${slug}` : `${routePrefix}/${slug}`).replace(/\/{2,}/g, '/');
  return base.startsWith('/') ? base.slice(1) : base;
}
export function getFirstJourneyPage(context) {
  if (!context?.relevantPages) {
    return undefined;
  }
  const lastPageReached = context.relevantPages.at(-1);
  const penultimatePageReached = context.relevantPages.at(-2);
  if (lastPageReached instanceof TerminalPageController && penultimatePageReached) {
    return penultimatePageReached;
  }
  return lastPageReached;
}
function resolveState(state) {
  return state === 'preview' ? FormStatus.Live : state;
}
function isPreviewState(state, options = {}) {
  return options.isPreview ?? state === 'preview';
}
//# sourceMappingURL=form-context.js.map