import { isSession } from "@remix-run/server-runtime";
export function createTypedSessionStorage({ sessionStorage, schema }) {
  return {
    async getSession(cookieHeader, options) {
      let session = await sessionStorage.getSession(cookieHeader, options);
      return await createTypedSession({ session, schema });
    },
    async commitSession(session, options) {
      // check if session.data is valid
      await schema.parseAsync(session.data);
      return await sessionStorage.commitSession(session, options);
    },
    async destroySession(session) {
      // check if session.data is valid
      await schema.parseAsync(session.data);
      return await sessionStorage.destroySession(session);
    },
  };
}
async function createTypedSession({ session, schema }) {
  // get a raw shape version of the schema but converting all the keys to their
  // flash versions.
  let flashSchema = {};
  for (let key in schema.shape) {
    flashSchema[flash(key)] = schema.shape[key].optional();
  }
  // parse session.data to add default values and remove invalid ones
  // we use strict mode here so we can throw an error if the session data
  // contains any invalid key, which is a sign that the session data is
  // corrupted.
  let data = await schema.extend(flashSchema).strict().parseAsync(session.data);
  return {
    get isTyped() {
      return true;
    },
    get id() {
      return session.id;
    },
    get data() {
      return data;
    },
    has(name) {
      let key = String(safeKey(schema, name));
      return key in data || flash(key) in data;
    },
    get(name) {
      let key = String(safeKey(schema, name));
      if (key in data) return data[key];
      let flashKey = flash(key);
      if (flashKey in data) {
        let value = data[flashKey];
        delete data[flashKey];
        return value;
      }
      return;
    },
    set(name, value) {
      let key = String(safeKey(schema, name));
      data[key] = value;
    },
    flash(name, value) {
      let key = String(safeKey(schema, name));
      let flashKey = flash(key);
      data[flashKey] = value;
    },
    unset(name) {
      let key = String(safeKey(schema, name));
      delete data[key];
    },
  };
}
/**
 * ReReturns true if an object is a Remix Utils typed session.
 *
 * @see https://github.com/sergiodxa/remix-utils#typed-session
 */
export function isTypedSession(value) {
  return isSession(value) && value.isTyped === true;
}
function flash(name) {
  return `__flash_${name}__`;
}
// checks that the key is a valid key of the schema
function safeKey(schema, key) {
  return schema.keyof().parse(key);
}
