<template>
  <div v-if="isButtonGroupDisplayable" class="btn-group">
    <button
      :class="
        Object.assign({
          btn: true,
          'btn-outline-primary': true,
          'dropdown-toggle': true,
          'btn-sm': props.small,
        })
      "
      type="button"
      data-bs-toggle="dropdown"
      aria-expanded="false"
    >
      Actions
    </button>
    <ul class="dropdown-menu">
      <li v-if="isEditableOnline">
        <wopi-edit-button
          :stored-object="props.storedObject"
          :classes="{ 'dropdown-item': true }"
          :execute-before-leave="props.executeBeforeLeave"
        ></wopi-edit-button>
      </li>
      <li v-if="isEditableOnDesktop">
        <desktop-edit-button
          :classes="{ 'dropdown-item': true }"
          :edit-link="props.davLink"
          :expiration-link="props.davLinkExpiration"
        ></desktop-edit-button>
      </li>
      <li v-if="isConvertibleToPdf">
        <convert-button
          :stored-object="props.storedObject"
          :filename="filename"
          :classes="{ 'dropdown-item': true }"
        ></convert-button>
      </li>
      <li v-if="isDownloadable">
        <download-button
          :stored-object="props.storedObject"
          :at-version="props.storedObject.currentVersion"
          :filename="filename"
          :classes="{ 'dropdown-item': true }"
          :display-action-string-in-button="true"
        ></download-button>
      </li>
      <li v-if="isHistoryViewable">
        <history-button
          :stored-object="props.storedObject"
          :can-edit="canEdit && props.storedObject._permissions.canEdit"
        ></history-button>
      </li>
    </ul>
  </div>
  <div v-else-if="'pending' === props.storedObject.status">
    <div class="btn btn-outline-info">Génération en cours</div>
  </div>
  <div v-else-if="'failure' === props.storedObject.status">
    <div class="btn btn-outline-danger">La génération a échoué</div>
  </div>
</template>

<script lang="ts" setup>
import { computed, onMounted } from "vue";
import ConvertButton from "./StoredObjectButton/ConvertButton.vue";
import DownloadButton from "./StoredObjectButton/DownloadButton.vue";
import WopiEditButton from "./StoredObjectButton/WopiEditButton.vue";
import {
  is_extension_editable,
  is_extension_viewable,
  is_object_ready,
} from "./StoredObjectButton/helpers";
import {
  StoredObject,
  StoredObjectStatusChange,
  StoredObjectVersion,
  WopiEditButtonExecutableBeforeLeaveFunction,
} from "../types";
import DesktopEditButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/DesktopEditButton.vue";
import HistoryButton from "ChillDocStoreAssets/vuejs/StoredObjectButton/HistoryButton.vue";

interface DocumentActionButtonsGroupConfig {
  storedObject: StoredObject;
  small?: boolean;
  canEdit?: boolean;
  canDownload?: boolean;
  canConvertPdf?: boolean;
  returnPath?: string;

  /**
   * Will be the filename displayed to the user when he·she download the document
   * (the document will be saved on his disk with this name)
   *
   * If not set, 'document' will be used.
   */
  filename?: string;

  /**
   * If set, will execute this function before leaving to the editor
   */
  executeBeforeLeave?: WopiEditButtonExecutableBeforeLeaveFunction;

  /**
   * a link to download and edit file using webdav
   */
  davLink?: string;

  /**
   * the expiration date of the download, as a unix timestamp
   */
  davLinkExpiration?: number;
}

const emit =
  defineEmits<
    (
      e: "onStoredObjectStatusChange",
      newStatus: StoredObjectStatusChange,
    ) => void
  >();

const props = withDefaults(defineProps<DocumentActionButtonsGroupConfig>(), {
  small: false,
  canEdit: true,
  canDownload: true,
  canConvertPdf: true,
  returnPath:
    window.location.pathname + window.location.search + window.location.hash,
});

/**
 * counter for the number of times that we check for a new status
 */
let tryiesForReady = 0;

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

const isButtonGroupDisplayable = computed<boolean>(() => {
  return (
    isDownloadable.value ||
    isEditableOnline.value ||
    isEditableOnDesktop.value ||
    isConvertibleToPdf.value
  );
});

const isDownloadable = computed<boolean>(() => {
  return (
    props.storedObject.status === "ready" ||
    // happens when the stored object version is just added, but not persisted
    (props.storedObject.currentVersion !== null &&
      props.storedObject.status === "empty")
  );
});

const isEditableOnline = computed<boolean>(() => {
  return (
    props.storedObject.status === "ready" &&
    props.storedObject._permissions.canEdit &&
    props.canEdit &&
    props.storedObject.currentVersion !== null &&
    is_extension_editable(props.storedObject.currentVersion.type) &&
    props.storedObject.currentVersion.persisted !== false
  );
});

const isEditableOnDesktop = computed<boolean>(() => {
  return isEditableOnline.value;
});

const isConvertibleToPdf = computed<boolean>(() => {
  return (
    props.storedObject.status === "ready" &&
    props.storedObject._permissions.canSee &&
    props.canConvertPdf &&
    props.storedObject.currentVersion !== null &&
    is_extension_viewable(props.storedObject.currentVersion.type) &&
    props.storedObject.currentVersion.type !== "application/pdf" &&
    props.storedObject.currentVersion.persisted !== false
  );
});

const isHistoryViewable = computed<boolean>(() => {
  return props.storedObject.status === "ready";
});

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

  tryiesForReady = tryiesForReady + 1;

  setTimeout(onObjectNewStatusCallback, 5000);
};

const onObjectNewStatusCallback = async function (): Promise<void> {
  if (props.storedObject.status === "stored_object_created") {
    return Promise.resolve();
  }

  const new_status = await is_object_ready(props.storedObject);
  if (props.storedObject.status !== new_status.status) {
    emit("onStoredObjectStatusChange", new_status);
    return Promise.resolve();
  } else if ("failure" === new_status.status) {
    return Promise.resolve();
  }

  if ("ready" !== new_status.status) {
    // we check for new status, unless it is ready
    checkForReady();
  }

  return Promise.resolve();
};

onMounted(() => {
  checkForReady();
});
</script>

<style scoped></style>
