<script>
import { authenticatedRequest } from "@/components/session/authenticatedRequest.vue";
import { computed, ref } from "vue";
import { parseError } from "@/components/request/HandleGlobalError.vue";
import { SuperUserObject } from "@/components/session/token/superUserObject.vue";
import { AdminUserObject } from "@/components/session/token/AdminUserObject.vue";
import { EditFieldForm } from "@/components/session/token/SessionUser/EditFieldForm.vue";
import { reCAPTCHA } from "@/components/session/token/SessionUser/reCAPTCHA/reCAPTCHA.vue";
import { Categories } from "@/components/session/token/SessionUser/Objects/Categories.vue";
import { Products } from "@/components/session/token/SessionUser/Objects/Products.vue";
import { ProductOptions } from "@/components/session/token/SessionUser/Objects/ProductOptions.vue";
import { Departments } from "@/components/session/token/SessionUser/Objects/Departments.vue";
import { DepartmentCategories } from "@/components/session/token/SessionUser/Objects/DepartmentCategories.vue";
import { EconomicDepartments } from "@/components/session/token/SessionUser/Objects/economicDepartments.vue";
import { EconomicProducts } from "@/components/session/token/SessionUser/Objects/economicProducts.vue";
import { Roles } from "@/components/session/token/SessionUser/Objects/Roles.vue";
import { Permissions } from "@/components/session/token/SessionUser/Objects/Permissions.vue";
import { CollectedOrderInvoices } from "@/components/session/token/SessionUser/Objects/CollectedOrderInvoices.vue";
import { DepartmentDailyReports } from "@/components/session/token/SessionUser/Objects/DepartmentDailyReports.vue";
import { DepartmentDailyReportComplaints } from "@/components/session/token/SessionUser/Objects/DepartmentDailyReportComplaints.vue";
import { Goals } from "@/components/session/token/SessionUser/Objects/Goals.vue";
import { Notifications } from "@/components/session/token/SessionUser/Objects/Notifications.vue";
import { Bookings } from "@/components/session/token/SessionUser/Objects/Bookings.vue";
import { Orders } from "@/components/session/token/SessionUser/Objects/Orders.vue";
import { Forms } from "@/components/session/token/SessionUser/Objects/Forms.vue";
import { Branding } from "@/components/session/token/SessionUser/Objects/Brandings.vue";
import { Vehicles } from "@/components/session/token/SessionUser/Objects/Vehicles.vue";
import { DepartmentNotificationSms } from "@/components/session/token/SessionUser/Objects/DepartmentNotificationSms.vue";
import { DepartmentTimeBookingsOpeningHours } from "@/components/session/token/SessionUser/Objects/DepartmentTimeBookingsOpeningHours.vue";
import { DepartmentTimeBookingsTypes } from "@/components/session/token/SessionUser/Objects/DepartmentTimeBookingsTypes.vue";
import { DepartmentTimeBookingsEntries } from "@/components/session/token/SessionUser/Objects/DepartmentTimeBookingsEntries.vue";
import { DepartmentVariables } from "@/components/session/token/SessionUser/Objects/DepartmentVariables.vue";
import { XLVaskVehicleTypes } from "@/components/session/token/SessionUser/Objects/XLVaskVehicleTypes.vue";
import { OpenAI } from "@/components/session/token/superUser/modules/openAI/OpenAI.vue";
import { DepartmentLanes } from "@/components/session/token/SessionUser/Objects/DepartmentLanes.vue";
import { DepartmentGates } from "@/components/session/token/SessionUser/Objects/DepartmentGates.vue";
import { DepartmentRelays } from "@/components/session/token/SessionUser/Objects/DepartmentRelays.vue";
import { OrderBookings } from "@/components/session/token/SessionUser/Objects/OrderBookings.vue";
import { ModuleActionLogs } from "@/components/session/token/SessionUser/Objects/ModuleActionLogs.vue";
import { SelfServeQuestions } from "@/components/session/token/SessionUser/Objects/SelfServeQuestions.vue";
import { SelfServeTasks } from "@/components/session/token/SessionUser/Objects/SelfServeTasks.vue";
import { SelfServeConditions } from "@/components/session/token/SessionUser/Objects/SelfServeConditions.vue";
import { SelfServeVehicleConditions } from "@/components/session/token/SessionUser/Objects/SelfServeVehicleConditions.vue";
import { SelfServeConditionRules } from "@/components/session/token/SessionUser/Objects/SelfServeConditionRules.vue";
import { SelfServeMachineTypes } from "@/components/session/token/SessionUser/Objects/SelfServeMachineTypes.vue";
import { ObjectsGlobal } from "@/components/session/token/SessionUser/Objects/ObjectsGlobal.vue";
import Swal from "sweetalert2";
import { SubuserGrants } from "@/components/session/token/SessionUser/Objects/SubuserGrants.vue";
import { Subusers } from "@/components/session/token/SessionUser/Objects/Subusers.vue";
import { configureReleaseRuntime } from "@/services/releaseTimeline.js";
import { fetchReleaseRuntime } from "@/services/releaseBootstrap.js";
import { pingApiServer } from "@/services/apiHealth.js";
import { normalizeSessionPayload } from "@/services/sessionPayload.js";
import {
  isReleaseChannelApiAvailabilityError,
  markReleaseChannelApiUnavailable,
  reconcileSelectedReleaseChannel,
  releaseChannelRuntimeRequestParams,
  setReleaseChannelSwitchNoticePrincipal,
} from "@/services/releaseChannelAvailability.js";
import { clearCachedXlvaskUsageAmount } from "@/components/displays/department/pos/sync/xlvaskUsageAmountCache.js";
import { clearEdgeGatewayWorkspaceCache } from "@/services/edgeGateways.js";
import {
  clearPeriodCache,
  clearSelfWashCountsCache,
} from "@/views/dashboards/superUserDashboard/InvoicingBillingPeriod/imports/InvoicingBillingPeriodImportPaging.js";

const normalizePositiveInteger = (value) => {
  const parsedValue = Number.parseInt(String(value ?? ""), 10);
  return Number.isInteger(parsedValue) && parsedValue > 0 ? parsedValue : null;
};

const SUBUSER_MANAGEMENT_PERMISSIONS = {
  list: {
    customer: "list_own_subusers",
    subuser: "SUBUSERS_LIST",
  },
  add: {
    customer: "add_own_subusers",
    subuser: "SUBUSERS_ADD",
  },
  edit: {
    customer: "edit_own_subusers",
    subuser: "SUBUSERS_EDIT",
  },
  delete: {
    customer: "delete_own_subusers",
    subuser: "SUBUSERS_DELETE",
  },
};

const CUSTOMER_FEATURE_PERMISSIONS = {
  vehicles: {
    list: {
      customer: ["user", "list_own_vehicles"],
      subuser: ["VEHICLES_LIST"],
    },
    add: {
      customer: ["user", "add_vehicle"],
      subuser: ["VEHICLES_ADD"],
    },
    edit: {
      customer: ["edit_vehicle", "add_vehicle"],
      subuser: ["VEHICLES_EDIT"],
    },
    delete: {
      customer: ["delete_vehicle"],
      subuser: ["VEHICLES_DELETE"],
    },
  },
  bookings: {
    list: {
      customer: ["user", "list_own_bookings"],
      subuser: ["BOOKINGS_LIST"],
    },
    add: {
      customer: ["user"],
      subuser: ["BOOKINGS_ADD"],
    },
    edit: {
      customer: ["edit_own_bookings"],
      subuser: ["BOOKINGS_EDIT"],
    },
    delete: {
      customer: ["delete_own_bookings"],
      subuser: ["BOOKINGS_DELETE"],
    },
  },
  orders: {
    list: {
      customer: ["user", "list_own_orders"],
      subuser: ["ORDERS_LIST"],
    },
    edit: {
      customer: ["edit_own_orders"],
      subuser: ["ORDERS_EDIT"],
    },
  },
  selfserve: {
    list: {
      customer: ["user", "list_own_department_selfserve_vehicle_conditions"],
      subuser: ["SELFSERVE_LIST"],
    },
    add: {
      customer: ["add_own_department_selfserve_vehicle_conditions"],
      subuser: ["SELFSERVE_ADD"],
    },
  },
  subusers: SUBUSER_MANAGEMENT_PERMISSIONS,
};

const getStoredSessionSnapshot = () => {
  if (typeof window === "undefined") {
    return null;
  }

  try {
    const token = window.localStorage.getItem("token");
    if (token === null) {
      return null;
    }

    return {
      token,
      isSubuser: window.localStorage.getItem("is_subuser") === "true",
      selectedCustomerNumber: normalizePositiveInteger(window.localStorage.getItem("selected_customer_number")),
    };
  } catch {
    return null;
  }
};

const hydrateSessionFromStorage = () => {
  const snapshot = getStoredSessionSnapshot();
  if (!snapshot) {
    return false;
  }

  SessionUser.token.value = snapshot.token;
  SessionUser.authenticated.value = true;
  SessionUser.isSubuser.value = snapshot.isSubuser;
  SessionUser.subuser.selectedGrantCustomerNumber.value = snapshot.selectedCustomerNumber;
  return true;
};

const clearPrivilegedSessionCaches = () => {
  clearPeriodCache();
  clearSelfWashCountsCache();
  clearCachedXlvaskUsageAmount();
  clearEdgeGatewayWorkspaceCache();
};

const clearStoredSession = () => {
  clearPrivilegedSessionCaches();

  if (typeof window === "undefined") {
    return;
  }

  try {
    window.localStorage.removeItem("token");
    window.localStorage.removeItem("is_subuser");
    window.localStorage.removeItem("selected_customer_number");
  } catch {
    // Storage can be unavailable in test or private browsing contexts.
  }
};

const applyReleaseRuntimeConfig = (runtime) => {
  const normalizedRuntime = runtime || {};
  configureReleaseRuntime(normalizedRuntime);
  reconcileSelectedReleaseChannel(normalizedRuntime);
  const runtimeUrls =
    normalizedRuntime.urls && typeof normalizedRuntime.urls === "object" ? normalizedRuntime.urls : {};
  SessionUser.runtimeConfig.release.traceId.value = normalizedRuntime.trace_id || null;
  SessionUser.runtimeConfig.release.channel.value = normalizedRuntime.channel || null;
  SessionUser.runtimeConfig.release.availableChannels.value =
    normalizedRuntime.available_channels || normalizedRuntime.availableChannels || [];
  SessionUser.runtimeConfig.release.versions.value = normalizedRuntime.versions || {
    frontend: null,
    api: null,
    bundle_id: null,
  };
  SessionUser.runtimeConfig.release.frontendBaseUrl.value =
    normalizedRuntime.frontend_base_url || runtimeUrls.frontend_base_url || null;
  SessionUser.runtimeConfig.release.apiBaseUrl.value =
    normalizedRuntime.api_base_url || runtimeUrls.api_base_url || null;
  SessionUser.runtimeConfig.release.availability.value = normalizedRuntime.availability || {
    configured: true,
    missing: [],
    status: "ready",
    explicit: false,
  };
  SessionUser.runtimeConfig.release.capturePolicy.value = normalizedRuntime.capture_policy || {
    enabled: false,
    capture_level: "metadata",
    all_failure_metadata: true,
    retention_days: 14,
  };
};

export const refreshReleaseRuntime = async ({ throwOnError = false } = {}) => {
  try {
    const runtime = await fetchReleaseRuntime();
    applyReleaseRuntimeConfig(runtime || {});
    return runtime || {};
  } catch (error) {
    console.warn("Could not refresh release runtime", error);
    if (throwOnError) {
      throw error;
    }
    return null;
  }
};

const resetSessionState = () => {
  SessionUser.user.id.value = null;
  SessionUser.user.customer_number.value = null;
  SessionUser.user.display_name.value = null;
  SessionUser.user.group_id.value = null;
  SessionUser.user.email.value = null;
  SessionUser.user.phone.number.value = null;
  SessionUser.user.phone.country_code.value = null;
  SessionUser.user.notifications.wash_certificate_email.value = null;
  SessionUser.user.notifications.email_notifications_enabled.value = null;
  SessionUser.user.notifications.sms_notifications_enabled.value = null;
  SessionUser.user.notifications.superuser_new_customer_email_notifications_enabled.value = null;
  SessionUser.user.created_at.value = null;
  SessionUser.user.updated_at.value = null;
  SessionUser.user.cached_at.value = null;
  SessionUser.permissions.value = [];
  SessionUser.token.value = null;
  SessionUser.authenticated.value = false;
  SessionUser.isSubuser.value = false;
  SessionUser.initiated.value = false;

  SessionUser.subuser.id.value = null;
  SessionUser.subuser.username.value = null;
  SessionUser.subuser.name.value = null;
  SessionUser.subuser.email.value = null;
  SessionUser.subuser.phone.country_code.value = null;
  SessionUser.subuser.phone.number.value = null;
  SessionUser.subuser.grants.value = [];
  SessionUser.subuser.created_at.value = null;
  SessionUser.subuser.updated_at.value = null;
  SessionUser.subuser.suspended_at.value = null;
  SessionUser.subuser.cached_at.value = null;
  SessionUser.subuser.selectedGrantCustomerNumber.value = null;

  if (typeof window !== "undefined") {
    try {
      window.localStorage.removeItem("selected_customer_number");
    } catch {
      // Storage is optional for the in-memory reset.
    }
  }

  SessionUser.economicData.customerNumber.value = null;
  SessionUser.economicData.name.value = null;
  SessionUser.economicData.address.value = null;
  SessionUser.economicData.zip.value = null;
  SessionUser.economicData.city.value = null;
  SessionUser.economicData.mobilePhone.value = null;
  SessionUser.economicData.email.value = null;
  SessionUser.economicData.cvr.value = null;
  SessionUser.economicData.currency.value = null;
  SessionUser.economicData.country.value = null;
  SessionUser.economicData.cached_at.value = null;

  SessionUser.runtimeConfig.economic.transactionDraftCustomerNumber.value = null;
  SessionUser.runtimeConfig.economic.defaultDistributionDepartmentId.value = null;
  SessionUser.runtimeConfig.release.traceId.value = null;
  SessionUser.runtimeConfig.release.channel.value = null;
  SessionUser.runtimeConfig.release.availableChannels.value = [];
  SessionUser.runtimeConfig.release.versions.value = { frontend: null, api: null, bundle_id: null };
  SessionUser.runtimeConfig.release.frontendBaseUrl.value = null;
  SessionUser.runtimeConfig.release.apiBaseUrl.value = null;
  SessionUser.runtimeConfig.release.availability.value = {
    configured: true,
    missing: [],
    status: "ready",
    explicit: false,
  };
  SessionUser.runtimeConfig.release.capturePolicy.value = {
    enabled: false,
    capture_level: "metadata",
    all_failure_metadata: true,
    retention_days: 14,
  };
  setReleaseChannelSwitchNoticePrincipal("");
  configureReleaseRuntime({});
};

const reconcileSelectedSubuserGrant = (grants) => {
  const grantList = Array.isArray(grants) ? grants : [];
  const currentSelection = normalizePositiveInteger(SessionUser.subuser.selectedGrantCustomerNumber.value);
  const validCustomerNumbers = grantList
    .map((grant) => normalizePositiveInteger(grant?.billing_customer_number))
    .filter((customerNumber) => customerNumber !== null);

  if (currentSelection && validCustomerNumbers.includes(currentSelection)) {
    SessionUser.subuser.selectGrant(currentSelection);
    return;
  }

  if (validCustomerNumbers.length === 1) {
    SessionUser.subuser.selectGrant(validCustomerNumbers[0]);
    return;
  }

  SessionUser.subuser.selectGrant(null);
};

let sessionBootstrapPromise = null;

const extractErrorMessage = (error) => {
  if (typeof error === "string") {
    return error;
  }

  if (error?.response?.data?.data?.message) {
    return error.response.data.data.message;
  }

  if (error?.response?.data?.message) {
    return error.response.data.message;
  }

  if (typeof error?.response?.data === "string") {
    return error.response.data;
  }

  if (error?.message) {
    return error.message;
  }

  return "";
};

export const isInvalidSessionError = (error) => {
  const status = Number.parseInt(String(error?.response?.status ?? ""), 10);
  const message = extractErrorMessage(error).toLowerCase();

  if (status === 401 || status === 419) {
    return true;
  }

  if (![400, 403].includes(status)) {
    return false;
  }

  return (
    message.includes("invalid session") ||
    message.includes("invalid token") ||
    message.includes("unauthenticated") ||
    message.includes("unauthorized")
  );
};

const redirectToConnectivityIssue = () => {
  if (typeof window === "undefined" || window.location.pathname === "/connectivity-issue") {
    return false;
  }

  window.location.href = "/connectivity-issue";
  return true;
};

export const handleSessionBootstrapFailure = async (error, { title, text } = {}) => {
  if (isInvalidSessionError(error)) {
    const wasSubuserSession = SessionUser.isSubuser.value || getStoredSessionSnapshot()?.isSubuser === true;
    const pingResult = await pingApiServer();
    if (!pingResult.ok) {
      console.warn("Preserving stored session because API ping failed during invalid-session handling.", pingResult);
      const redirected = redirectToConnectivityIssue();
      return {
        cleared: false,
        apiReachable: false,
        ping: pingResult,
        redirectedTo: redirected ? "/connectivity-issue" : null,
      };
    }

    forceClearSession();
    if (wasSubuserSession) {
      SessionUser.functions.redirectTo.pages.subuserLogin();
      return { cleared: true, apiReachable: true, ping: pingResult, redirectedTo: "/login/driver" };
    }
    SessionUser.functions.redirectTo.pages.login();
    return { cleared: true, apiReachable: true, ping: pingResult, redirectedTo: "/login" };
  }

  parseError(error, "auth");
  console.error(error);
  await Swal.fire({
    title,
    text,
    icon: "error",
    confirmButtonText: "Ok",
  });

  return { cleared: false, apiReachable: null, ping: null, redirectedTo: null };
};

export const refreshSessionData = async () => {
  if (!hydrateSessionFromStorage()) {
    resetSessionState();
    return null;
  }

  if (SessionUser.isSubuser.value) {
    return await getSubuserSessionData();
  }

  return await getSessionData();
};

/**
 * Initiate the user session on app start
 * @returns {Promise<void>}
 */
export const initiateOnAppStart = async ({ force = false } = {}) => {
  if (sessionBootstrapPromise && !force) {
    return await sessionBootstrapPromise;
  }

  const bootstrapPromise = (async () => {
    if (!hydrateSessionFromStorage()) {
      return null;
    }

    if (SessionUser.isSubuser.value) {
      return await getSubuserSessionData();
    }

    return await getSessionData();
  })();

  sessionBootstrapPromise = bootstrapPromise;

  try {
    return await bootstrapPromise;
  } finally {
    if (sessionBootstrapPromise === bootstrapPromise) {
      sessionBootstrapPromise = null;
    }
  }
};

/**
 * Authenticate the user
 * @param {string} customer_number
 * @param {string} password
 * @returns {Promise<void>}
 */
export const authenticateUser = async (customer_number, password) => {
  return await authenticatedRequest("/auth/login", "POST", {
    customer_number,
    password,
  })
    .then((response) => {
      clearPrivilegedSessionCaches();
      SessionUser.token.value = response.data.token;
      SessionUser.authenticated.value = true;
      localStorage.setItem("token", response.data.token);
      localStorage.removeItem("is_subuser");
      // Reload the window to make sure the user's session is initiated
      window.location.reload();
    })
    .catch((error) => {
      parseError(error, "auth");
      console.error(error);
    });
};

/**
 * Authenticate a subuser with password
 * Supports three authentication methods:
 * - phone_country_code + phone + password
 * - subuser_id + password
 * - username + password
 * @param {Object} credentials - The authentication credentials
 * @param {number} [credentials.phone_country_code] - Phone country code (1-3 digits)
 * @param {number} [credentials.phone] - Phone number (4-15 digits)
 * @param {number} [credentials.subuser_id] - Subuser ID
 * @param {string} [credentials.username] - Username
 * @param {string} credentials.password - Password (8-255 characters, uppercase, lowercase, and number)
 * @returns {Promise<void>}
 */
export const authenticateSubuser = async (credentials) => {
  const { phone_country_code, phone, subuser_id, username, password } = credentials;

  // Build the request body based on provided credentials
  let requestBody = { password };

  if (phone_country_code !== undefined && phone !== undefined) {
    requestBody.phone_country_code = phone_country_code;
    requestBody.phone = phone;
  } else if (subuser_id !== undefined) {
    requestBody.subuser_id = subuser_id;
  } else if (username !== undefined) {
    requestBody.username = username;
  } else {
    throw new Error("Invalid credentials: must provide phone_country_code+phone, subuser_id, or username");
  }

  return await authenticatedRequest("/subusers/auth/password", "POST", requestBody)
    .then((response) => {
      clearPrivilegedSessionCaches();
      SessionUser.token.value = response.data.data.session;
      SessionUser.authenticated.value = true;
      SessionUser.isSubuser.value = true;
      console.warn("Subuser session initiated", response);
      // Make sure the subuser's session is valid before setting the token and reloading
      if (!response.data.data.session) {
        throw new Error("No session token received for subuser authentication");
      }
      localStorage.setItem("token", response.data.data.session);
      localStorage.setItem("is_subuser", "true");
      // Reload the window to make sure the subuser's session is initiated
      window.location.reload();
    })
    .catch((error) => {
      parseError(error, "auth");
      console.error(error);
      throw error;
    });
};

/**
 * Get the subuser's session data from /subusers/me
 * @returns {Promise<void>}
 */
export const getSubuserSessionData = async () => {
  return await authenticatedRequest("/subusers/me", "GET")
    .then(async (response) => {
      const data = response.data.data || response.data;
      SessionUser.subuser.id.value = data.id;
      SessionUser.subuser.username.value = data.username;
      SessionUser.subuser.name.value = data.name;
      SessionUser.subuser.email.value = data.email;
      SessionUser.subuser.phone.country_code.value = data.phone_country_code;
      SessionUser.subuser.phone.number.value = data.phone;
      SessionUser.subuser.grants.value = data.grants || [];
      reconcileSelectedSubuserGrant(SessionUser.subuser.grants.value);
      SessionUser.subuser.created_at.value = data.created_at;
      SessionUser.subuser.updated_at.value = data.updated_at;
      SessionUser.subuser.suspended_at.value = data.suspended_at;
      SessionUser.subuser.cached_at.value = new Date();
      setReleaseChannelSwitchNoticePrincipal(`subuser:${data.id || data.username || data.email || "unknown"}`);

      // Build permissions from grants
      const allPermissions = [];
      if (data.grants && Array.isArray(data.grants)) {
        data.grants.forEach((grant) => {
          if (grant.permissions && Array.isArray(grant.permissions)) {
            allPermissions.push(...grant.permissions);
          }
        });
      }
      SessionUser.permissions.value = [...new Set(allPermissions)];
      await refreshReleaseRuntime();
      SessionUser.initiated.value = true;
    })
    .catch(async (error) => {
      if (isReleaseChannelApiAvailabilityError(error)) {
        console.warn("Selected release channel API is unavailable during session bootstrap.", error);
        markReleaseChannelApiUnavailable();
        return;
      }

      return await handleSessionBootstrapFailure(error, {
        title: "Fejl ved hentning af subbrugerdata",
        text: "Der opstod en fejl ved hentning af dine brugerdata. Prøv at logge ind igen.",
      });
    });
};

/**
 * Get the user's session data
 * @returns {Promise<void>}
 */
export const getSessionData = async () => {
  return await authenticatedRequest("/auth/session", "GET", releaseChannelRuntimeRequestParams())
    .then((response) => {
      const session = normalizeSessionPayload(response?.data?.data);

      SessionUser.user.id.value = session.id;
      SessionUser.user.customer_number.value = session.customer_number;
      SessionUser.user.group_id.value = session.group_id;
      SessionUser.user.email.value = session.email;
      SessionUser.user.phone.number.value = session.phone.number;
      SessionUser.user.phone.country_code.value = session.phone.country_code;
      SessionUser.user.notifications.wash_certificate_email.value = session.notifications.wash_certificate_email;
      SessionUser.user.notifications.email_notifications_enabled.value =
        session.notifications.email_notifications_enabled;
      SessionUser.user.notifications.sms_notifications_enabled.value = session.notifications.sms_notifications_enabled;
      SessionUser.user.notifications.superuser_new_customer_email_notifications_enabled.value =
        session.notifications.superuser_new_customer_email_notifications_enabled;
      SessionUser.user.created_at.value = session.created_at;
      SessionUser.user.updated_at.value = session.updated_at;
      SessionUser.user.display_name.value = session.display_name;
      setReleaseChannelSwitchNoticePrincipal(
        `user:${session.id || session.customer_number || session.email || "unknown"}`
      );
      // Set the last cached time to now, this is used to determine if the user's data is outdated
      SessionUser.user.cached_at.value = new Date();
      SessionUser.permissions.value = session.permissions;
      SessionUser.runtimeConfig.economic.transactionDraftCustomerNumber.value = normalizePositiveInteger(
        session.runtime_config.economic.transaction_draft_customer_number
      );
      SessionUser.runtimeConfig.economic.defaultDistributionDepartmentId.value = normalizePositiveInteger(
        session.runtime_config.economic.default_distribution_department_id
      );
      applyReleaseRuntimeConfig(session.runtime_config.release);
      // E-conomic data is only fetched if the array isn't empty
      if (session.economic_customer) {
        SessionUser.economicData.customerNumber.value = session.economic_customer.customerNumber;
        SessionUser.economicData.name.value = session.economic_customer.name;
        // Set the display name to the e-conomic name if it's empty
        if (SessionUser.user.display_name.value === null || SessionUser.user.display_name.value === "Unnamed") {
          SessionUser.user.display_name.value = session.economic_customer.name;
        }
        SessionUser.economicData.address.value = session.economic_customer.address;
        SessionUser.economicData.zip.value = session.economic_customer.zip;
        SessionUser.economicData.city.value = session.economic_customer.city;
        SessionUser.economicData.mobilePhone.value = session.economic_customer.mobilePhone;
        SessionUser.economicData.email.value = session.economic_customer.email;
        SessionUser.economicData.cvr.value = session.economic_customer.corporateIdentificationNumber;
        SessionUser.economicData.currency.value = session.economic_customer.currency;
        SessionUser.economicData.country.value = session.economic_customer.country;
        SessionUser.economicData.cached_at.value = new Date();
      }
      SessionUser.initiated.value = true;
    })
    .catch(async (error) => {
      if (isReleaseChannelApiAvailabilityError(error)) {
        console.warn("Selected release channel API is unavailable during session bootstrap.", error);
        markReleaseChannelApiUnavailable();
        return;
      }

      return await handleSessionBootstrapFailure(error, {
        title: "Fejl ved hentning af brugerdata",
        text: "Der opstod en fejl ved hentning af dine brugerdata. Prøv at logge ind igen.",
      });
    });
};

const LOGOUT_REQUEST_TIMEOUT_MS = 2500;

const waitForLogoutRequest = async (request, timeoutMs = LOGOUT_REQUEST_TIMEOUT_MS) => {
  const safeTimeoutMs = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : LOGOUT_REQUEST_TIMEOUT_MS;
  let timeoutId = null;
  let didTimeout = false;

  const timeoutPromise = new Promise((resolve) => {
    timeoutId = globalThis.setTimeout(() => {
      didTimeout = true;
      resolve({ timedOut: true });
    }, safeTimeoutMs);
  });

  const requestPromise = Promise.resolve(request)
    .catch((error) => {
      if (!didTimeout) {
        parseError(error, "auth");
        console.error(error);
      }
      return { timedOut: false };
    })
    .finally(() => {
      if (timeoutId !== null) {
        globalThis.clearTimeout(timeoutId);
      }
    });

  return await Promise.race([requestPromise, timeoutPromise]);
};

/**
 * Destroy the user's session
 * @returns {Promise<void>}
 */
export const destroySession = async ({ timeoutMs = LOGOUT_REQUEST_TIMEOUT_MS } = {}) => {
  try {
    if (localStorage.getItem("token")) {
      await waitForLogoutRequest(authenticatedRequest("/auth/logout", "GET"), timeoutMs);
    }
  } finally {
    clearStoredSession();
    resetSessionState();
  }
};

/**
 * Force sign out the user
 */
export const forceClearSession = () => {
  clearStoredSession();
  resetSessionState();
};

/**
 * Define the user session variables
 */
export const SessionUser = {
  user: {
    id: ref(null),
    customer_number: ref(null),
    display_name: ref(null),
    group_id: ref(null),
    email: ref(null),
    phone: {
      number: ref(null),
      country_code: ref(null),
    },
    created_at: ref(null),
    updated_at: ref(null),
    cached_at: ref(null),
    notifications: {
      wash_certificate_email: ref(null),
      email_notifications_enabled: ref(null),
      sms_notifications_enabled: ref(null),
      superuser_new_customer_email_notifications_enabled: ref(null),
      setEmailNotificationsEnabled: (enabled) => {
        return SessionUser.request("/account/notifications", "PUT", {
          email_notifications_enabled: enabled,
        })
          .then(() => {
            SessionUser.user.notifications.email_notifications_enabled.value = enabled;
          })
          .catch((error) => {
            parseError(error, "user_notifications");
            console.error(error);
          });
      },
      setSmsNotificationsEnabled: (enabled) => {
        return SessionUser.request("/account/notifications", "PUT", {
          sms_notifications_enabled: enabled,
        })
          .then(() => {
            SessionUser.user.notifications.sms_notifications_enabled.value = enabled;
          })
          .catch((error) => {
            parseError(error, "user_notifications");
            console.error(error);
          });
      },
      setSuperuserNewCustomerEmailNotificationsEnabled: (enabled) => {
        return SessionUser.request("/account/notifications", "PUT", {
          superuser_new_customer_email_notifications_enabled: enabled,
        })
          .then(() => {
            SessionUser.user.notifications.superuser_new_customer_email_notifications_enabled.value = enabled;
          })
          .catch((error) => {
            parseError(error, "user_notifications");
            console.error(error);
          });
      },
      setWashCertificateEmail: (email) => {
        return SessionUser.request("/account/notifications", "PUT", {
          wash_certificate_email: email,
        })
          .then(() => {
            SessionUser.user.notifications.wash_certificate_email.value = email;
          })
          .catch((error) => {
            parseError(error, "user_notifications");
            console.error(error);
          });
      },
    },
  },
  /** Subuser profile data (populated when authenticated as subuser) */
  subuser: {
    id: ref(null),
    username: ref(null),
    name: ref(null),
    email: ref(null),
    phone: {
      country_code: ref(null),
      number: ref(null),
    },
    grants: ref([]),
    created_at: ref(null),
    updated_at: ref(null),
    suspended_at: ref(null),
    cached_at: ref(null),
    /** Currently selected grant (billing_customer_number) for X-Customer-Number header */
    selectedGrantCustomerNumber: ref(normalizePositiveInteger(localStorage.getItem("selected_customer_number"))),
    /**
     * Select a grant by billing_customer_number
     * @param {number|null} customerNumber - The billing_customer_number to select, or null to clear
     */
    selectGrant: (customerNumber) => {
      clearEdgeGatewayWorkspaceCache();
      const normalizedCustomerNumber = normalizePositiveInteger(customerNumber);
      if (normalizedCustomerNumber === null) {
        localStorage.removeItem("selected_customer_number");
        SessionUser.subuser.selectedGrantCustomerNumber.value = null;
      } else {
        localStorage.setItem("selected_customer_number", normalizedCustomerNumber.toString());
        SessionUser.subuser.selectedGrantCustomerNumber.value = normalizedCustomerNumber;
      }
    },
    /**
     * Get the currently selected grant object
     * @returns {Object|null} The selected grant object or null
     */
    getSelectedGrant: () => {
      const selectedNum = SessionUser.subuser.selectedGrantCustomerNumber.value;
      if (!selectedNum || !SessionUser.subuser.grants.value) return null;
      return SessionUser.subuser.grants.value.find((g) => g.billing_customer_number === selectedNum) || null;
    },
  },
  /** Whether the current session is a subuser session */
  isSubuser: ref(false),
  /** The user's permissions */
  permissions: ref([]),
  availableVirtualPermissions: ["has_superuser_token"],
  runtimeConfig: {
    economic: {
      transactionDraftCustomerNumber: ref(null),
      defaultDistributionDepartmentId: ref(null),
    },
    release: {
      traceId: ref(null),
      channel: ref(null),
      availableChannels: ref([]),
      versions: ref({ frontend: null, api: null }),
      frontendBaseUrl: ref(null),
      apiBaseUrl: ref(null),
      availability: ref({
        configured: true,
        missing: [],
        status: "ready",
      }),
      capturePolicy: ref({
        enabled: false,
        capture_level: "metadata",
        all_failure_metadata: true,
        retention_days: 14,
      }),
    },
  },
  virtualPermissions: computed(() => {
    /** These permissions are NOT set by default for superusers, this should ONLY be used for superusers */
    let virtualPermissions = [];
    // Super user token
    // Check if the user has a superuser token in the local storage
    if (localStorage.getItem("superuser_token") !== null) {
      // Validate the superuser token
      if (localStorage.getItem("superuser_token") !== SessionUser.token.value) {
        virtualPermissions.push("has_superuser_token");
      }
    }
    return virtualPermissions;
  }),
  permissions_computed: computed(() => {
    return [...SessionUser.permissions.value];
  }),
  hasPermission: (permission) => {
    //console.log('Checking permission: ' + permission + ' - ' + hasPermission);
    // Check if the permission is virtual
    if (SessionUser.availableVirtualPermissions.values().toArray().includes(permission)) {
      console.warn("Virtual permission detected: " + permission);
      return SessionUser.virtualPermissions.value.values().toArray().includes(permission);
    }
    // For subusers, check permissions from the selected grant only
    if (SessionUser.isSubuser.value) {
      const selectedGrant = SessionUser.subuser.getSelectedGrant();
      if (selectedGrant && selectedGrant.permissions) {
        return selectedGrant.permissions.includes(permission);
      }
      return false;
    }
    return SessionUser.permissions.value.includes(permission) || SessionUser.permissions.value.includes("superuser");
  },
  hasAnyPermission: (permissions = []) => {
    const permissionList = Array.isArray(permissions) ? permissions : [permissions].filter(Boolean);
    if (permissionList.length === 0) {
      return true;
    }
    return permissionList.some((permission) => SessionUser.hasPermission(permission));
  },
  /** Can access shortcuts */
  canAccessAdmin: () => {
    return SessionUser.hasPermission("admin") || SessionUser.hasPermission("superuser");
  },
  canAccessSuperUser: () => {
    return SessionUser.hasPermission("superuser");
  },
  canAccessUser: () => {
    return SessionUser.hasPermission("user");
  },
  canManageSubusers: (action) => {
    const permissions = SUBUSER_MANAGEMENT_PERMISSIONS[action];
    if (!permissions) {
      return false;
    }
    return SessionUser.isSubuser.value
      ? SessionUser.hasPermission(permissions.subuser)
      : SessionUser.hasPermission(permissions.customer);
  },
  canAccessCustomerFeature: (feature, action = "list") => {
    const permissions = CUSTOMER_FEATURE_PERMISSIONS[feature]?.[action];
    if (!permissions) {
      return false;
    }

    const permissionList = SessionUser.isSubuser.value ? permissions.subuser : permissions.customer;
    return SessionUser.hasAnyPermission(permissionList);
  },
  canAccessDepartment: (id = 0) => {
    return SessionUser.hasPermission("department_access_" + parseInt(id)) || SessionUser.canAccessSuperUser();
  },
  canAccessAssignedDepartment: (id = 0) => {
    const departmentId = parseInt(id, 10);
    if (!Number.isInteger(departmentId)) {
      return false;
    }

    const permission = "department_access_" + departmentId;
    if (SessionUser.isSubuser.value) {
      const selectedGrant = SessionUser.subuser.getSelectedGrant();
      if (selectedGrant && selectedGrant.permissions) {
        return selectedGrant.permissions.includes(permission);
      }
    }

    return SessionUser.permissions.value.includes(permission);
  },
  canAccessDeveloper: () => {
    // If the url is localhost, we can assume that the user is a developer
    return window.location.hostname === "localhost";
  },
  canAccessGuest: () => {
    return true; // All users can access guest features
  },
  hasToken: () => {
    return SessionUser.token.value !== null || hydrateSessionFromStorage();
  },
  /** Shortcuts for the user's group */
  superUser: SuperUserObject,
  adminUser: AdminUserObject,

  /** Objects */
  objects: {
    categories: Categories,
    products: Products,
    product_options: ProductOptions,
    departments: Departments,
    department_categories: DepartmentCategories,
    economic_departments: EconomicDepartments,
    economic_products: EconomicProducts,
    roles: Roles,
    permissions: Permissions,
    collectedOrderInvoices: CollectedOrderInvoices,
    department_daily_reports: DepartmentDailyReports,
    department_daily_report_complaints: DepartmentDailyReportComplaints,
    goals: Goals,
    notifications: Notifications,
    orders: Orders,
    forms: Forms,
    bookings: Bookings,
    Branding: Branding,
    vehicles: Vehicles,
    department_notification_sms: DepartmentNotificationSms,
    department_time_bookings_opening_hours: DepartmentTimeBookingsOpeningHours,
    department_time_bookings_types: DepartmentTimeBookingsTypes,
    department_time_bookings_entries: DepartmentTimeBookingsEntries,
    department_variables: DepartmentVariables,
    xlvask_vehicle_types: XLVaskVehicleTypes,
    openai: OpenAI,
    department_lanes: DepartmentLanes,
    department_gates: DepartmentGates,
    department_relays: DepartmentRelays,
    order_bookings: OrderBookings,
    module_action_logs: ModuleActionLogs,
    self_serve_questions: SelfServeQuestions,
    self_serve_tasks: SelfServeTasks,
    self_serve_conditions: SelfServeConditions,
    self_serve_vehicle_conditions: SelfServeVehicleConditions,
    self_serve_condition_rules: SelfServeConditionRules,
    self_serve_machine_types: SelfServeMachineTypes,
    subusers: Subusers,
    subuser_grants: SubuserGrants,
    global: ObjectsGlobal,
  },
  /** The user's token and authentication status */
  token: ref(null),
  authenticated: ref(false),
  /** The user's e-conomic data */
  economicData: {
    customerNumber: ref(null),
    name: ref(null),
    address: ref(null),
    zip: ref(null),
    city: ref(null),
    mobilePhone: ref(null),
    email: ref(null),
    cvr: ref(null),
    currency: ref(null),
    country: ref(null),
    cached_at: ref(null),
  },
  /** Check if the user's data is outdated (Older than 24 hours) */
  isDataOutdated: () => {
    return new Date() - SessionUser.user.cached_at.value > 1000 * 60 * 60 * 24;
  },
  /** Check if the user's e-conomic data is outdated (Older than 24 hours) */
  isEconomicDataOutdated: () => {
    return new Date() - SessionUser.economicData.cached_at.value > 1000 * 60 * 60 * 24;
  },
  /** Check if the user has e-conomic data */
  hasEconomicData: () => {
    return SessionUser.economicData.customerNumber.value !== null;
  },
  getCustomerNumber: () => {
    return SessionUser.user.customer_number.value;
  },
  /** Is the object fully initiated */
  initiated: ref(false),
  isInitiated: () => {
    return SessionUser.initiated.value;
  },
  /**
   * Check if the user has a superuser token stored (This is used when the superuser is impersonating a user)
   * @returns {boolean}
   */
  hasSuperUserToken: () => {
    return localStorage.getItem("superuser_token") !== null;
  },
  /**
   * Set the user's token
   * @param {string} token
   */
  setToken: (token) => {
    clearPrivilegedSessionCaches();
    SessionUser.token.value = token;
    localStorage.setItem("token", token);
    // Reload the window to make sure the user's session is initiated
    window.location.reload();
  },
  /**
   * Does the user have a specific attribute (Basically just a link to check if the user has permission`has_attribute_{{attribute}}`) // E.g. hasAttribute('admin') would check if the user has the 'has_attribute_key_admin' permission
   * @param {string} attribute
   * @returns {boolean}
   */
  hasAttribute: (attribute) => {
    return SessionUser.hasPermission("has_attribute_" + attribute);
  },
  /**
   * Get the user's display name
   */
  getName: () => {
    // If the user is a subuser, return the subuser's name
    if (SessionUser.isSubuser.value) {
      return SessionUser.subuser.name.value || SessionUser.subuser.username.value || "Unnamed";
    }
    return SessionUser.user.display_name.value || "Unnamed";
  },
  /** Reset the user's session data (Cache) */
  forceRefresh: () => {
    resetSessionState();
  },
  auth: {
    /** Authenticate the user */
    authenticate: authenticateUser,
    /** Authenticate a subuser with password */
    authenticateSubuser: authenticateSubuser,
    /** Logout the user */
    logout: destroySession,
    /** Force clear the user's local session state and stored token */
    forceClearSession: forceClearSession,
    /** reCAPTCHA */
    reCAPTCHA: reCAPTCHA,
  },
  functions: {
    /** Contact functions */
    contact: {
      onClickCallPhoneNumber: () => {
        // Call the phone number
        window.location.href = "tel:+4543717886";
      },
    },
    /** Device type checks */
    device: {
      dimensions: {
        // Using breakpoints in accordance with Bulma CSS framework
        // https://bulma.io/documentation/start/responsiveness/#breakpoints
        mobileMaxWidth: 768,
        tabletMinWidth: 769,
        tabletMaxWidth: 1023,
        desktopMinWidth: 1024,
        desktopMaxWidth: 1215,
        widescreenMinWidth: 1216,
        widescreenMaxWidth: 1407,
        fullhdMinWidth: 1408,
        // Custom additions
        fullhdMaxWidth: 1919,
        ultrawideMinWidth: 1920,
        ultrawideMaxWidth: 3840,
      },
      isMobile: () => {
        return windowInnerWidth.value < SessionUser.functions.device.dimensions.tabletMinWidth;
        //return /Mobi|Android/i.test(navigator.userAgent);
      },
      isDesktop: () => {
        return windowInnerWidth.value >= SessionUser.functions.device.dimensions.desktopMinWidth;
        //return !/Mobi|Android/i.test(navigator.userAgent);
      },
      isTablet: () => {
        return (
          windowInnerWidth.value >= SessionUser.functions.device.dimensions.tabletMinWidth &&
          windowInnerWidth.value <= SessionUser.functions.device.dimensions.tabletMaxWidth
        );
        //return /Tablet|iPad/i.test(navigator.userAgent);
      },
      isWidescreen: () => {
        return (
          windowInnerWidth.value >= SessionUser.functions.device.dimensions.widescreenMinWidth &&
          windowInnerWidth.value <= SessionUser.functions.device.dimensions.widescreenMaxWidth
        );
      },
      isFullHD: () => {
        return windowInnerWidth.value >= SessionUser.functions.device.dimensions.fullhdMinWidth;
      },
      isUltraWideScreen: () => {
        return windowInnerWidth.value >= SessionUser.functions.device.dimensions.ultrawideMinWidth;
      },
    },
    /** Check if the user has a token */
    hasToken: () => {
      return SessionUser.token.value !== null || hydrateSessionFromStorage();
    },
    ucFirst: (str) => {
      return str.charAt(0).toUpperCase() + str.slice(1);
    },
    /** Select department */
    selectDepartment: (departmentId) => {
      // Check if the department id is valid
      if (isNaN(departmentId) || departmentId <= 0) {
        console.error("Invalid department id: " + departmentId);
        return;
      }
      if (departmentId === "default") {
        // Redirect to the default department page
        SessionUser.functions.redirectTo.department("");
        return;
      }
      // Check if the user has access to the department
      if (!SessionUser.canAccessDepartment(departmentId)) {
        console.error("User does not have access to department: " + departmentId);
        return;
      }
      // Check if the current path is within the /admin/:departmentId route
      if (!window.location.pathname.startsWith("/admin/")) {
        // Redirect to the department page
        SessionUser.functions.redirectTo.department(departmentId);
        return;
      }
      // Get the router instance
      // Change the department in the url (while keeping the current path)
      const currentPath = window.location.pathname;
      // If
      // If the current path is not an admin path, redirect to the department page
      const newPath = currentPath
        .replace(/\/admin\/\d+/, "")
        .replace(/^\/admin\/?/, "")
        .replace(/^\//, "");
      const shouldPreserveCurrentQuery = newPath === "modules/pos" || newPath.startsWith("modules/pos/");
      const queryString = shouldPreserveCurrentQuery ? window.location.search : "";
      // Redirect to the department page
      SessionUser.functions.redirectTo.department(departmentId, newPath + queryString);
    },
    /** Show confirm logout dialog */
    showConfirmLogoutDialog: () => {
      return Swal.fire({
        title: "Er du sikker?",
        text: "Du vil blive logget ud af systemet",
        icon: "warning",
        showCancelButton: true,
        confirmButtonText: "Ja, log mig ud",
        cancelButtonText: "Annuller",
      }).then(async (result) => {
        if (result.isConfirmed) {
          const wasSubuserSession = SessionUser.isSubuser.value || getStoredSessionSnapshot()?.isSubuser === true;
          try {
            await SessionUser.auth.logout();
          } finally {
            SessionUser.auth.forceClearSession();
            if (wasSubuserSession) {
              SessionUser.functions.redirectTo.pages.subuserLogin();
              return;
            }
            SessionUser.functions.redirectTo.pages.login();
          }
        }
      });
    },
    /** Get the department id from the url */
    getDepartmentIdFromUrl: () => {
      // Avoid router import cycles by parsing the current pathname directly.
      const path = window.location.pathname || "";
      const match = path.match(/^\/admin\/(\d+)(?:\/|$)/);
      if (!match) {
        return undefined;
      }
      const departmentId = Number.parseInt(match[1], 10);
      return Number.isInteger(departmentId) && departmentId > 0 ? departmentId : undefined;
    },
    /** Get the department ids the user has access to */
    getAccessibleDepartments: () => {
      return SessionUser.permissions.value
        .filter((permission) => permission.includes("department_access_"))
        .map((permission) => parseInt(permission.split("_").pop()));
    },
    currency: {
      toLocal: (value) => {
        return new Intl.NumberFormat("da-DK", { style: "currency", currency: "DKK" }).format(value);
      },
    },
    text: {
      truncate: (text, length = 25) => {
        return text.length > length ? text.substring(0, length) + "..." : text;
      },
    },
    date: {
      // Format to 2023-01-01 12:00:00
      format: (date) => {
        return new Date(date).toISOString().slice(0, 19).replace("T", " ");
      },
      toWords: (date) => {
        const options = { weekday: "long", year: "numeric", month: "long", day: "numeric" };
        return new Date(date).toLocaleDateString("da-DK", options);
      },
      toLocal: (date) => {
        return new Date(date).toLocaleString("da-DK");
      },
      toWordsWithTime: (date) => {
        const options = {
          weekday: "long",
          year: "numeric",
          month: "long",
          day: "numeric",
          hour: "2-digit",
          minute: "2-digit",
        };
        return new Date(date).toLocaleDateString("da-DK", options);
      },
      isToday(date) {
        const created_at_val = new Date(date);
        const today = new Date();
        return created_at_val.toDateString() === today.toDateString();
      },
      toLocalTimeHours: (date) => {
        return new Date(date).toLocaleTimeString("da-DK", { hour: "2-digit", minute: "2-digit" });
      },
      getDateWeekdayNumber: (date) => {
        const created_at_val = new Date(date);
        const weekday = created_at_val.getDay();
        return weekday === 0 ? 7 : weekday;
      },
      timeAgo: (date) => {
        // Returns e.g. "5 minutter siden"
        const now = new Date();
        const past = new Date(date);
        const secondsAgo = Math.floor((now - past) / 1000);
        const intervals = {
          year: 31536000,
          month: 2592000,
          week: 604800,
          day: 86400,
          hour: 3600,
          minute: 60,
          second: 1,
        };
        for (const [unit, secondsInUnit] of Object.entries(intervals)) {
          const interval = Math.floor(secondsAgo / secondsInUnit);
          if (interval >= 1) {
            // If the unit is singular or plural in danish
            if (interval === 1) {
              const unitSingularMap = {
                year: "år",
                month: "måned",
                week: "uge",
                day: "dag",
                hour: "time",
                minute: "minut",
                second: "sekund",
              };
              return interval + " " + unitSingularMap[unit] + " siden";
            } else {
              const unitPluralMap = {
                year: "år",
                month: "måneder",
                week: "uger",
                day: "dage",
                hour: "timer",
                minute: "minutter",
                second: "sekunder",
              };
              return interval + " " + unitPluralMap[unit] + " siden";
            }
          }
        }
        return "lige nu";
      },
      weekdayNumbers: {
        monday: 1,
        tuesday: 2,
        wednesday: 3,
        thursday: 4,
        friday: 5,
        saturday: 6,
        sunday: 7,
      },
      getDateMonthStart() {
        return new Date(new Date().getFullYear(), new Date().getMonth(), 1);
      },
      getDateMonthEnd() {
        return new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0);
      },
      getDateMonthName(date) {
        console.log(date);
        return new Date(date).toLocaleString("da-DK", { month: "long" });
      },
      getDateYear(date) {
        return new Date(date).getFullYear();
      },
      getDateAtTime(date, hours, minutes, seconds) {
        const newDate = new Date(date);
        newDate.setHours(hours);
        newDate.setMinutes(minutes);
        newDate.setSeconds(seconds);
        return newDate;
      },
      getWeekdayNameToLocal(date) {
        return new Date(date).toLocaleString("da-DK", { weekday: "long" });
      },
    },
    /** Redirect to */
    redirectTo: {
      /**
       * Pages to redirect to
       */
      pages: {
        login: () => {
          window.location.href = "/login";
        },
        subuserLogin: () => {
          window.location.href = "/login/driver";
        },
        redirect: () => {
          window.location.href = "/redirect";
        },
      },
      /**
       * Redirect to a department
       * @note This will redirect the user to '/admin/:department(/:path)'
       * @param department The department id
       * @param path The path to redirect to (Optional)
       * @param new_tab Open the url in a new tab
       */
      department: (department, path = null, new_tab = false) => {
        if (!!new_tab) {
          SessionUser.functions.redirectTo.external("/admin/" + department + (path !== null ? "/" + path : ""), true);
        } else {
          window.location.href = "/admin/" + department + (path !== null ? "/" + path : "");
        }
      },
      /**
       * Redirect to a superuser page
       * @note This will redirect the user to '/superuser(/:path)'
       * @param path The path to redirect to (Optional)
       * @param new_tab Open the url in a new tab
       */
      superUser: (path = null, new_tab = false) => {
        if (new_tab) {
          window.open("/superuser" + (path !== null ? path : ""), "_blank");
          return;
        }
        window.location.href = "/superuser" + (path !== null ? path : "");
      },
      /**
       * Redirect to a user page
       * @note This will redirect the user to '/user(/:path)'
       * @param path The path to redirect to (Optional)
       * @param new_tab Open the url in a new tab
       */
      user: (path = null, new_tab = false) => {
        if (new_tab) {
          window.open("/user" + (path !== null ? path : ""), "_blank");
          return;
        }
        window.location.href = "/user" + (path !== null ? path : "");
      },
      /**
       * External redirect
       * @param url The url to redirect to
       * @param newTab Open the url in a new tab
       */
      external: (url, newTab = false) => {
        if (newTab) {
          window.open(url, "_blank");
        } else {
          window.location.href = url;
        }
      },
    },
    parseErrorMessage(error) {
      console.log("Parsing error message: ", error);
      // Check if the error is a string
      if (typeof error === "string") {
        return error;
      }
      // check if the response.data.data.message exists
      if (error.response && error.response.data && error.response.data.data && error.response.data.data.message) {
        return error.response.data.data.message;
      }
      // check if the response.data.message exists
      if (error.response && error.response.data && error.response.data.message) {
        return error.response.data.message;
      }
      // check if the response.data exists
      if (error.response && error.response.data) {
        return error.response.data;
      }
      // check if the response exists
      if (error.response) {
        return error.response;
      }
    },
    getBusinessDaysBetweenDates(start, end, weekdays = ["MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY"]) {
      let count = 0;
      const curDate = new Date(start);
      while (curDate <= end) {
        const dayOfWeek = curDate.toLocaleString("en-US", { weekday: "long" }).toUpperCase();
        if (weekdays.includes(dayOfWeek)) {
          count++;
        }
        curDate.setDate(curDate.getDate() + 1);
      }
      return count;
    },
  },
  request: authenticatedRequest,
  editField: EditFieldForm,
  getSessionData: getSessionData,
  getSubuserSessionData: getSubuserSessionData,
  refreshSessionData: refreshSessionData,
  refreshReleaseRuntime: refreshReleaseRuntime,
  initiateOnAppStart: initiateOnAppStart,
  checkForUpdates() {
    // Check if this is the latest version of the PWA
  },
};

const windowInnerWidth = ref(window.innerWidth);
const updateWindowInnerWidth = () => {
  windowInnerWidth.value = window.innerWidth;
};
window.addEventListener("resize", updateWindowInnerWidth);

export default SessionUser;
</script>
