<script setup lang="ts">
import { Trash2 } from 'lucide-vue-next';
import { onMounted, onUnmounted, Ref, ref } from 'vue';
import { BmsIconButton } from '@/index';

const files: Ref<File[] | undefined> = ref();
const isDragOver = ref(false);

const props = withDefaults(
  defineProps<{
    dragOverMessage?: string;
    dragOffMessage?: string;
    modelValue?: File[];
    limit: number;
  }>(),
  {
    limit: 10,
    dragOverMessage: 'Déposer votre image ici',
    dragOffMessage: 'Glissez votre image ici ou cliquez pour parcourir',
  },
);

const emit = defineEmits(['update:modelValue']);

onMounted(() => {
  window.addEventListener('dragover', onDragStartEvent);
  window.addEventListener('dragleave', onDragEndEvent);
});

onUnmounted(() => {
  window.removeEventListener('dragover', onDragStartEvent);
  window.addEventListener('dragleave', onDragEndEvent);
});

function onDragStartEvent() {
  isDragOver.value = true;
}

function onDragEndEvent() {
  isDragOver.value = false;
}

async function onSelectFile(event: Event) {
  const target = event?.target as HTMLInputElement;
  const file = target?.files?.[0];

  if (!file) {
    return;
  }

  try {
    await checkSize(file);

    isDragOver.value = false;
    emit('update:modelValue', [file]);
  } catch (error) {
    alert(error);
    return;
  }
}

function checkSize(file: File): Promise<boolean> {
  return new Promise((resolve, reject) => {
    if (file.size / 1048576 > props.limit) {
      reject(`Le fichier dépasse la limite autorisée de ${props.limit}Mo`);

      return;
    }

    resolve(true);
  });
}

async function onDropFile(event: DragEvent) {
  if (!event.dataTransfer?.files) {
    return;
  }

  const file = event.dataTransfer?.files[0];

  try {
    await checkSize(file);

    isDragOver.value = false;
    emit('update:modelValue', [file]);
  } catch (error) {
    alert(error);
    return;
  }
}

function onDeleteFile(file: File) {
  emit(
    'update:modelValue',
    files.value?.filter((f) => f !== file),
  );
}
</script>

<template>
  <div class="file-upload">
    <div
      v-if="!modelValue || !modelValue.length"
      class="file-upload__drop-area"
      :class="{ 'is-active': isDragOver }"
      data-testid="file-upload-drop-area"
      @drop.prevent="onDropFile($event)"
      @dragover.prevent
    >
      <label class="file-upload__label">
        <template v-if="isDragOver">{{ dragOverMessage }}</template>
        <template v-else>{{ dragOffMessage }}</template>
        <input
          data-testid="file-upload-input-file"
          type="file"
          @change="onSelectFile($event)"
        />
      </label>
    </div>

    <div v-else>
      <template v-if="modelValue.length">
        <div
          v-for="file in modelValue"
          :key="file.name"
          class="file-upload__file"
        >
          <span class="file-upload__file-name">
            {{ file.name }}
          </span>
          <BmsIconButton @click="onDeleteFile(file)"><Trash2 /></BmsIconButton>
        </div>
      </template>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.file-upload {
  --drop-color: var(--bms-grey-10);

  &__label {
    display: block;
    padding: 4em 1em;
    text-align: center;
    border-radius: var(--bms-border-radius);
    border: 1px dashed var(--bms-border-color);
    background: var(--drop-color);

    &:hover {
      --drop-color: var(--bms-grey-25);
    }
  }

  &__drop-area {
    input[type='file'] {
      opacity: 0;
      position: absolute;
      pointer-events: none;
      left: 0;
      width: 0;
      height: 0;
    }

    &.is-active {
      --drop-color: var(--bms-main-25);
    }
  }

  &__file {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.5em 0.5em 0.5em 1em;
    border-radius: var(--bms-border-radius);
    border: 1px solid var(--bms-grey-25);
    background: var(--bms-grey-10);

    &-name {
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
      flex: 1 1 auto;
    }

    .button {
      flex: 0 0 auto;
    }
  }
}
</style>
