<script setup lang="ts">
import {
  trans,
  SAVED_EXPORT_EXECUTE,
  EXPORT_GENERATION_EXPORT_GENERATION_IS_PENDING_SHORT,
  EXPORT_GENERATION_TOO_MANY_RETRIES,
  EXPORT_GENERATION_ERROR_WHILE_GENERATING_EXPORT,
  EXPORT_GENERATION_EXPORT_READY,
} from "translator";
import {
  fetchExportGenerationStatus,
  generateFromSavedExport,
} from "ChillMainAssets/lib/api/export";
import { computed, ref } from "vue";
import { ExportGeneration } from "ChillMainAssets/types";
import { StoredObject, StoredObjectStatus } from "ChillDocStoreAssets/types";
import DownloadButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/DownloadButton.vue";
import { useToast } from "vue-toast-notification";
import "vue-toast-notification/dist/theme-sugar.css";

interface SavedExportButtonGenerateConfig {
  savedExportUuid: string;
}

const props = defineProps<SavedExportButtonGenerateConfig>();
const emits = defineEmits<{
  (e: "generate");
}>();

const toast = useToast();
const exportGeneration = ref<ExportGeneration | null>(null);

const status = computed<StoredObjectStatus | "inactive">(
  () => exportGeneration.value?.status ?? "inactive",
);
const storedObject = computed<null | StoredObject>(() => {
  if (exportGeneration.value === null) {
    return null;
  }

  return exportGeneration.value?.storedObject;
});

const isInactive = computed<boolean>(() => status.value === "inactive");
const isPending = computed<boolean>(() => status.value === "pending");
const isFetching = computed<boolean>(
  () => tryiesForReady.value < maxTryiesForReady,
);
const isReady = computed<boolean>(() => status.value === "ready");
const isFailure = computed<boolean>(() => status.value === "failure");
const filename = computed<string>(() => {
  if (null === exportGeneration.value) {
    return "";
  }

  return `${exportGeneration.value?.storedObject.title}-${exportGeneration.value?.createdAt?.datetime8601}`;
});
const externalDownloadLink = computed<string>(
  () => `/fr/main/export-generation/${exportGeneration.value?.id}/wait`,
);
const classes = computed<Record<string, boolean>>(() => {
  return {};
});
const buttonClasses = computed<Record<string, boolean>>(() => {
  return { btn: true, "btn-outline-primary": true };
});

/**
 * counter for the number of times that we check for a new status
 */
let tryiesForReady = ref<number>(0);

/**
 * how many times we may check for a new status, once loaded
 */
const maxTryiesForReady = 120;

const checkForReady = function (): void {
  if (
    "ready" === status.value ||
    "empty" === status.value ||
    "failure" === status.value ||
    // stop reloading if the page stays opened for a long time
    tryiesForReady.value > maxTryiesForReady
  ) {
    return;
  }

  tryiesForReady.value = tryiesForReady.value + 1;
  setTimeout(
    onObjectNewStatusCallback,
    tryiesForReady.value < 10 ? 1500 : 5000,
  );
};

const onExportGenerationSuccess = function (): void {
  toast.success(trans(EXPORT_GENERATION_EXPORT_READY));
};

const onObjectNewStatusCallback = async function (): Promise<void> {
  if (null === exportGeneration.value) {
    checkForReady();
    return Promise.resolve();
  }

  const newExportGeneration = await fetchExportGenerationStatus(
    exportGeneration.value?.id,
  );

  if (newExportGeneration.status !== exportGeneration.value.status) {
    if (newExportGeneration.status === "ready") {
      onExportGenerationSuccess();
    }
  }

  exportGeneration.value = newExportGeneration;

  if (isPending.value) {
    checkForReady();
    return Promise.resolve();
  }

  return Promise.resolve();
};

const onClickGenerate = async (): Promise<void> => {
  emits("generate");
  exportGeneration.value = await generateFromSavedExport(props.savedExportUuid);

  onObjectNewStatusCallback();

  return Promise.resolve();
};
</script>

<template>
  <button
    v-if="isInactive"
    :class="buttonClasses"
    type="button"
    @click="onClickGenerate"
  >
    <i class="fa fa-cog"></i> {{ trans(SAVED_EXPORT_EXECUTE) }}
  </button>
  <template v-if="isPending && isFetching">
    <span class="btn">
      <i class="fa fa-cog fa-spin fa-fw"></i>
      <span class="pending-message">{{
        trans(EXPORT_GENERATION_EXPORT_GENERATION_IS_PENDING_SHORT)
      }}</span>
      <a :href="externalDownloadLink" class="externalDownloadLink">
        <i class="bi bi-box-arrow-up-right"></i>
      </a>
    </span>
  </template>
  <div v-if="isPending && !isFetching" :class="buttonClasses">
    <span>{{ trans(EXPORT_GENERATION_TOO_MANY_RETRIES) }}</span>
  </div>
  <download-button
    v-else-if="isReady && storedObject?.currentVersion !== null"
    :classes="buttonClasses"
    :stored-object="storedObject"
    :at-version="storedObject?.currentVersion"
    :filename="filename"
  ></download-button>
  <div v-else-if="isFailure" :class="classes">
    <span class="btn">
      <i class="bi bi-exclamation-triangle"></i>
      <span class="pending-message">{{
        trans(EXPORT_GENERATION_ERROR_WHILE_GENERATING_EXPORT)
      }}</span>
    </span>
  </div>
</template>

<style scoped lang="scss">
.pending-message {
  font-style: italic;
}

.externalDownloadLink {
  margin-left: 1rem;
}
</style>
