<script setup lang="ts">
import { StoredObject, StoredObjectVersionCreated } from "../../types";
import {
  encryptFile,
  fetchNewStoredObject,
  uploadVersion,
} from "../../js/async-upload/uploader";
import { computed, ref, Ref } from "vue";
import FileIcon from "ChillDocStoreAssets/vuejs/FileIcon.vue";

interface DropFileConfig {
  existingDoc?: StoredObject;
}

const props = withDefaults(defineProps<DropFileConfig>(), {
  existingDoc: null,
});

const emit =
  defineEmits<
    (
      e: "addDocument",
      {
        stored_object_version: StoredObjectVersionCreated,
        stored_object: StoredObject,
        file_name: string,
      },
    ) => void
  >();

const is_dragging: Ref<boolean> = ref(false);
const uploading: Ref<boolean> = ref(false);
const display_filename: Ref<string | null> = ref(null);

const has_existing_doc = computed<boolean>(() => {
  return props.existingDoc !== undefined && props.existingDoc !== null;
});

const onDragOver = (e: Event) => {
  e.preventDefault();

  is_dragging.value = true;
};

const onDragLeave = (e: Event) => {
  e.preventDefault();

  is_dragging.value = false;
};

const onDrop = (e: DragEvent) => {
  e.preventDefault();

  const files = e.dataTransfer?.files;

  if (null === files || undefined === files) {
    console.error("no files transferred", e.dataTransfer);
    return;
  }
  if (files.length === 0) {
    console.error("no files given");
    return;
  }

  handleFile(files[0]);
};

const onZoneClick = (e: Event) => {
  e.stopPropagation();
  e.preventDefault();

  const input = document.createElement("input");
  input.type = "file";
  input.addEventListener("change", onFileChange);

  input.click();
};

const onFileChange = async (event: Event): Promise<void> => {
  const input = event.target as HTMLInputElement;

  if (input.files && input.files[0]) {
    console.log("file added", input.files[0]);
    const file = input.files[0];
    await handleFile(file);

    return Promise.resolve();
  }

  throw "No file given";
};

const handleFile = async (file: File): Promise<void> => {
  uploading.value = true;
  display_filename.value = file.name;
  const type = file.type;

  // create a stored_object if not exists
  let stored_object;
  if (null === props.existingDoc) {
    stored_object = await fetchNewStoredObject();
  } else {
    stored_object = props.existingDoc;
  }

  const buffer = await file.arrayBuffer();
  const [encrypted, iv, jsonWebKey] = await encryptFile(buffer);
  const filename = await uploadVersion(encrypted, stored_object);

  const stored_object_version: StoredObjectVersionCreated = {
    filename: filename,
    iv: Array.from(iv),
    keyInfos: jsonWebKey,
    type: type,
    persisted: false,
  };

  const fileName = file.name;
  let file_name = "Nouveau document";
  const file_name_split = fileName.split(".");
  if (file_name_split.length > 1) {
    const extension = file_name_split
      ? file_name_split[file_name_split.length - 1]
      : "";
    file_name = fileName.replace(extension, "").slice(0, -1);
  }

  emit("addDocument", {
    stored_object,
    stored_object_version,
    file_name: file_name,
  });
  uploading.value = false;
};
</script>

<template>
  <div class="drop-file">
    <div
      v-if="!uploading"
      :class="{ area: true, dragging: is_dragging }"
      @click="onZoneClick"
      @dragover="onDragOver"
      @dragleave="onDragLeave"
      @drop="onDrop"
    >
      <p v-if="has_existing_doc" class="file-icon">
        <file-icon :type="props.existingDoc?.type"></file-icon>
      </p>

      <p v-if="display_filename !== null" class="display-filename">
        {{ display_filename }}
      </p>
      <!-- todo i18n -->
      <p v-if="has_existing_doc">
        Déposez un document ou cliquez ici pour remplacer le document existant
      </p>
      <p v-else>
        Déposez un document ou cliquez ici pour ouvrir le navigateur de fichier
      </p>
    </div>
    <div v-else class="waiting">
      <i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
      <span class="sr-only">Loading...</span>
    </div>
  </div>
</template>

<style scoped lang="scss">
.drop-file {
  width: 100%;

  .file-icon {
    font-size: xx-large;
  }

  .display-filename {
    font-variant: small-caps;
    font-weight: 200;
  }

  & > .area,
  & > .waiting {
    width: 100%;
    height: 10rem;

    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;

    p {
      // require for display in DropFileModal
      text-align: center;
    }
  }

  & > .area {
    border: 4px dashed #ccc;

    &.dragging {
      border: 4px dashed blue;
    }
  }
}
</style>
