<script setup lang="ts">
import FileUpload from 'primevue/fileupload';
import VHint from '../hint/VHint.vue';
import VLabel from '../label/VLabel.vue';
import VButton from '../button/VButton.vue';
import VButtonGroup from '../button/VButtonGroup.vue';
import VFile from './VFile.vue';
import VMessage from '../message/VMessage.vue';
import type IVFileUpload from './IVFileUpload.type';
import type { FileUploadErrorEvent, FileUploadProgressEvent, FileUploadRemoveEvent, FileUploadSelectEvent, FileUploadUploadEvent } from 'primevue/fileupload';
import { computed, useId, ref, onMounted } from 'vue';
import styles from '@visua/typography.module.css';

defineOptions({
  inheritAttrs: false,
})

const fileUploadRef = ref();
const fileProgressMap = ref<Record<string, number>>({});

defineExpose({
  upload: () => fileUploadRef.value.upload()
});

const props = withDefaults(defineProps<IVFileUpload>(), {
  id: () => useId(),
  label: 'Ajouter un fichier',
  validMessage: '',
  hint: '',
  disabled: false,
  invalidFileSizeMessage: 'Taille de fichier invalide, la taille du fichier doit être plus petite que {1.}',
  invalidFileLimitMessage: 'Nombre maximal des fichiers atteint, le nombre maximal est {0.}',
  invalidFileTypeMessage: 'Type de fichier invalide, le type de fichier {0} n\'est pas pris en charge',
  accept: undefined,
  chooseLabel: 'Choisir',
  name: undefined,
  url: undefined,
  maxFileSize: undefined,
  fileLimit: undefined,
  withCredentials: false,
  previewWidth: 50,
  uploadLabel: 'Téléverser',
  cancelLabel: 'Annuler',
  showCancelButton: true,
  showUploadButton: true,
  advanced: false,
})

const emit = defineEmits([
  'select',
  'before-upload',
  'progress',
  'upload',
  'error',
  'before-send',
  'clear',
  'remove',
  'removeUploadFile',
  'uploader',
]);
const fileSelected = ref(false);
const hasActiveError = ref(false);

const lastSelectedFile = ref<File | null>(null);

const handleSelect = (event: FileUploadSelectEvent) => {
  emit('select', event);

  if (!props.advanced && event.files.length > 0 && fileUploadRef.value) {
    fileUploadRef.value.clear();
    fileUploadRef.value.files.push(event.files[event.files.length - 1]);
  }
  fileSelected.value = true;
};


const handleClear = () => {
  emit('clear');
  fileSelected.value = false;
  lastSelectedFile.value = null;
  hasActiveError.value = false;
};

const handleUpload = (event: FileUploadUploadEvent) => {
  totalSize.value = 0;
  totalSizePercent.value = 100;
  emit('upload', event);
  hasActiveError.value = false;
};


const handleRemove = (event: FileUploadRemoveEvent) => {
  emit('remove', event);
  fileSelected.value = false;
  lastSelectedFile.value = null;
  hasActiveError.value =false;
};

const handleProgress = (event: FileUploadProgressEvent) => {
  emit('progress', event);

  const files = fileUploadRef.value?.files || [];
  files.forEach((file: File) => {
    fileProgressMap.value[file.name] = event.progress;
  });
};

const handleError = (event: FileUploadErrorEvent) => {
  emit('error', event);
  hasActiveError.value = true;
}

const error = computed(() => hasActiveError.value);


const isSimpleAndEmpty = computed(() => {
  return !props.advanced && !fileSelected.value;
});

onMounted(() => {
  const currentFiles = fileUploadRef.value?.files || [];
  fileSelected.value = currentFiles.length > 0;
});

const totalSize = ref(0);
const totalSizePercent = ref(0);

const uploadEvent = (callback: () => void) => {
  totalSizePercent.value = totalSize.value / 10;
  callback();
  fileUploadRef.value.upload();
};

const padding = computed(() => props.advanced ? '1.125rem' : '0rem')
const borderColor = computed(() => props.advanced ? 'var(--border-default-grey)' : 'transparent');

const getLastFileSelected = (files: File[]) => {
  const indexOfLastFileSelected = files.length - 1;
  return files[indexOfLastFileSelected];
}

const labelState = computed(() => {
  if(!error.value && !props.disabled) return 'default';
  else if(error.value && !props.disabled) return 'error';
  else return undefined
})

type MessageType = 'alert' | 'warning' | 'success' | 'info';

const globalStatusMessage = computed<{
  type: MessageType;
  title: string;
} | null>(() => {
  const files = fileUploadRef.value?.files || [];
  const uploaded = fileUploadRef.value?.uploadedFiles || [];

  const hasError = files.some((f: { status: string; }) => f.status === 'error');
  const hasPending = files.length > 0;

  if (hasError) return { type: 'alert', title: 'Erreur lors du téléversement' };
  if (hasPending) return { type: 'warning', title: 'En attente de téléversement' };
  if (uploaded.length > 0) return { type: 'success', title: 'Tous les fichiers ont été téléversés' };
  return null;
});


</script>

<template>
  <div class="container">
    <VLabel
      :for="`file-upload-${props.id}`"
      :label="props.label"
      :disabled="props.disabled"
      :type="labelState"
      :hint="props.hint"
    />
    <FileUpload
      ref="fileUploadRef"
      :id="`file-upload-${props.id}`"
      :multiple="props.advanced"
      :invalid-file-limit-message="props.invalidFileLimitMessage"
      :invalid-file-size-message="props.invalidFileSizeMessage"
      :invalid-file-type-message="props.invalidFileTypeMessage"
      mode="advanced"
      :accept="props.accept"
      :disabled="props.disabled"
      v-bind="$attrs"
      :auto="!props.advanced"
      :choose-label="props.chooseLabel"
      :upload-label="props.uploadLabel"
      :cancel-label="props.cancelLabel"
      :name="props.name"
      :url="props.url"
      :max-file-size="props.maxFileSize"
      :file-limit="props.fileLimit"
      :with-credentials="props.withCredentials"
      :preview-width="props.previewWidth"
      :show-cancel-button="props.showCancelButton"
      :show-upload-button="props.showUploadButton"
      @select="handleSelect($event)"
      @before-send="emit('before-send', $event)"
      @progress="handleProgress($event)"
      @before-upload="emit('before-upload', $event)"
      @uploader="emit('uploader', $event)"
      @upload="handleUpload($event)"
      @error="handleError($event)"
      @clear="handleClear()"
      @remove="handleRemove($event)"
      @remove-uploaded-file="emit('removeUploadFile', $event)"
      class="p-fileupload"
    >
      <template #header="slotProps">
        <div v-if="props.advanced" class="advanced-fileupload-header">
          <VButtonGroup
            :buttons="[
              {
                label: 'Parcourir...',
                onClick: slotProps.chooseCallback,
                title: 'parcourir les fichiers',
              },
              {
                label: 'Téléverser',
                icon: 'ri-upload-cloud-line',
                onClick: () => uploadEvent(slotProps.uploadCallback),
                secondary: true,
                disabled: !slotProps.files || slotProps.files.length === 0,
                title: 'televerser les fichiers'
              },
              {
                label: 'Supprimer',
                tertiary: true,
                onClick: slotProps.clearCallback,
                disabled: !slotProps.files || slotProps.files.length === 0,
                title: 'suprimer les fichiers'
              }
            ]"
            size="sm"
            :disabled="props.disabled"
            inlineLayoutWhen="always"
            title="boutons de gestion des fichiers"
          />
          <VMessage
            v-if="globalStatusMessage"
            :type="globalStatusMessage.type"
            :title="globalStatusMessage.title"
          />
        </div>
        <div v-else class="simple-fileupload-header">
          <VButton label="Parcourir..." :disabled="props.disabled" size="sm" @click="slotProps.chooseCallback" title="parcourir les fichiers"/>
          <span
            v-if="isSimpleAndEmpty"
            :class="[styles['text-body-SM-detail-text-Regular']]"
          >
            Aucun fichier sélectionné
          </span>
        </div>
      </template>
      <template #content="slotProps" v-if="!isSimpleAndEmpty">
        <div v-if="props.advanced" class="advanced-container-content">
          <div class="fileupload-content">
            <div v-if="slotProps.files.length > 0">
              <div class="file-area">
                <VFile
                  v-for="(file, index) in slotProps.files"
                  :key="file.name + file.type + file.size"
                  :file="file"
                  :index="index"
                  :remove-file-callback="slotProps.removeFileCallback"
                  :progress="fileProgressMap[file.name] || 0"
                  status="pending"
                  advanced
                />
              </div>
              </div>
              <div v-if="slotProps.uploadedFiles.length > 0" class="fileupload-content">
                <div class="file-area">
                  <VFile
                    v-for="(file, index) in slotProps.uploadedFiles"
                    :key="file.name + file.type + file.size"
                    :file="file"
                    :index="index"
                    :remove-file-callback="slotProps.removeFileCallback"
                    :progress="100"
                    status="completed"
                    advanced
                  />
                </div>
              </div>
          </div>
        </div>
        <div v-else-if="slotProps.files.length > 0" class="simple-container-content">
          <VFile
            :file="getLastFileSelected(slotProps.files)"
            :remove-file-callback="slotProps.removeFileCallback"
          />
        </div>
        <VHint
          v-for="message of slotProps.messages"
          :key="message"
          :title="message"
          type="alert"
          icon
        />
      </template>
      <template #empty v-if="props.advanced">
        <div class="fileupload-empty" v-if="props.advanced">
          <i class="ri-upload-cloud-line upload-cloud-icon"></i>
          <p>Glissez-déposez les fichiers ici pour les téléverser.</p>
        </div>
      </template>
    </FileUpload>
  </div>
</template>

<style lang="css" scoped>
*{
  margin: 0px;
  padding: 0px;
}

.container {
  width: 100%;
  height: auto;
  display: flex;
  flex-direction: column;
  align-items: start;
  gap: 0.5rem;
}

.p-fileupload{
  width: 100%;
  --p-fileupload-border-color: v-bind(borderColor);
  padding: v-bind(padding);
}

.simple-fileupload-header{
  display: flex;
  flex-direction: row;
  gap: var(--p-fileupload-basic-gap);
  align-items: baseline;
  padding: 0px;
}

.advanced-fileupload-header{
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--p-fileupload-content-gap);
  margin-bottom: 0.75rem;
}

.fileupload-empty{
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
}

.upload-cloud-icon{
  font-size: 5rem;
  color: var(--border-contrast-grey);
}

.file-area{
  margin-top: 0.75rem;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.25rem;
}
</style>
