<script setup lang="ts">
import { onBeforeMount, onMounted } from "vue";
import { useCookies } from "vue3-cookies";
import { useRoute, useRouter } from "vue-router";
import { client } from "@/client/sdk.gen.ts";
import { environment } from "@/environment";
import AppHeader from "@/components/AppHeader.vue";
import AppFooter from "@/components/AppFooter.vue";
import {
  useNameStore,
  useUserStore,
  useResourceStore,
  useWorkflowStore,
  useBucketStore,
  useS3KeyStore,
  useS3ObjectStore,
  useOTRStore,
  useWorkflowExecutionStore,
  useNewsStore,
} from "@/stores";
import { stringify as param_stringify } from "qs";
import { OwnershipTypeEnum } from "@/client/types.gen";

const { cookies } = useCookies();
const router = useRouter();
const route = useRoute();
const userRepository = useUserStore();
const nameRepository = useNameStore();
const resourceRepository = useResourceStore();
const workflowRepository = useWorkflowStore();
const bucketRepository = useBucketStore();
const s3KeyRepository = useS3KeyStore();
const objectRepository = useS3ObjectStore();
const otrRepository = useOTRStore();
const executionRepository = useWorkflowExecutionStore();
const newsStore = useNewsStore();

onBeforeMount(() => {
  client.setConfig({
    baseURL: environment.API_BASE_URL,
    paramsSerializer: (params) =>
      param_stringify(params, { arrayFormat: "repeat" }),
  });
  userRepository.updateJWT(cookies.get("clowm-jwt"));
  if (userRepository.authenticated) {
    userRepository.getCurrentUser();
  }
  client.instance.interceptors.response.use(
    (res) => res,
    (err) => {
      if (
        err.response.status === 401 ||
        (err.response.status === 400 &&
          err.response.data.detail?.includes("JWT"))
      ) {
        userRepository.logout();
        router.push({
          name: "login",
          query: {
            login_error:
              err.response.status === 401
                ? "session token invalid"
                : "session expired",
            next: route.name !== "login" ? encodeURI(route.path) : undefined,
          },
        });
      }
      return Promise.reject(err);
    },
  );
  router.afterEach((to, from) => {
    window._paq?.push(["setReferrerUrl", from.path]);
    window._paq?.push(["deleteCustomVariables", "page"]);
    window._paq?.push(["deleteCustomDimension", 1]);
    const mtm_query_keys = Object.keys(to.query ?? {}).filter((key) =>
      key.startsWith("mtm_"),
    );
    const mtm_query =
      mtm_query_keys.length > 0
        ? mtm_query_keys
            .slice(1)
            .reduce(
              (prev, cur) => prev + `&${cur}=${to.query[cur]}`,
              `?${mtm_query_keys[0]}=${to.query[mtm_query_keys[0]]}`,
            )
        : "";
    window._paq?.push(["setCustomUrl", to.path + mtm_query]);
    window._paq?.push(["setDocumentTitle", to.name]);
    if (userRepository.currentUID.length > 0) {
      window._paq?.push(["setUserId", userRepository.currentUID]);
    }
    window._paq?.push(["trackPageView"]);
    window._paq?.push(["enableLinkTracking"]);
  });
  router.beforeEach((to) => {
    // redirect path that start with '/dashboard' to ensure backwards compatibility
    if (/^\/dashboard\/[\w]+/.test(to.fullPath)) {
      return to.fullPath.slice(10);
    }
  });
  router.beforeEach(async (to) => {
    // make sure the user is authenticated
    if (to.meta.public) {
      return;
    }
    if (
      !userRepository.authenticated &&
      // ❗️ Avoid an infinite redirect
      to.name !== "login"
    ) {
      // redirect the user to the login page and preserve query params for login error message
      return {
        name: "login",
        query: { ...to.query, next: encodeURI(to.path) },
      };
    } else if (
      to.meta.requiresDeveloperRole &&
      !(userRepository.workflowDev || userRepository.admin)
    ) {
      return { name: "workflows" };
    } else if (
      to.meta.requiresReviewerRole &&
      !(userRepository.reviewer || userRepository.admin)
    ) {
      return "/";
    } else if (
      to.meta.requiresMaintainerRole &&
      !(userRepository.resourceMaintainer || userRepository.admin)
    ) {
      return { name: "resources" };
    } else if (to.meta.adminRole && !userRepository.admin) {
      return "/";
    } else if (to.name !== "login" && to.query.next) {
      // return to original path after login
      return { path: decodeURI(to.query.next as string) };
    }
  });
  nameRepository.loadNameMapping();
});

onMounted(() => {
  if (userRepository.authenticated) {
    Promise.all([
      s3KeyRepository.fetchS3Keys(),
      bucketRepository.fetchOwnBuckets(),
    ]).then(() => {
      Promise.all(
        bucketRepository.buckets
          .filter((bucket) => bucket.owner_id === userRepository.currentUID)
          .map((bucket) => objectRepository.fetchMultipartUploads(bucket.name)),
      );
    });
    resourceRepository.fetchPublicResources();
    workflowRepository.fetchWorkflows();
    otrRepository.fetchOwnOtrs(OwnershipTypeEnum.BUCKET);
    executionRepository.fetchExecutions();
    newsStore.fetchCurrentNews();
    if (!userRepository.foreignUser) {
      bucketRepository.fetchOwnPermissions();
    }
    if (userRepository.workflowDev || userRepository.admin) {
      workflowRepository.fetchOwnWorkflows();
      otrRepository.fetchOwnOtrs(OwnershipTypeEnum.WORKFLOW);
    }
    if (userRepository.resourceMaintainer || userRepository.admin) {
      resourceRepository.fetchOwnResources();
      otrRepository.fetchOwnOtrs(OwnershipTypeEnum.RESOURCE);
    }
    if (userRepository.admin) {
      resourceRepository.fetchSyncRequests();
    }
  }
});
</script>

<template>
  <AppHeader />
  <div class="container-fluid container-xxxl mt-2 flex-grow-1 py-2">
    <router-view />
  </div>
  <AppFooter />
</template>

<style scoped></style>