<script lang="ts">
  import { popupState } from '@components/popup/Popup.ts';
  import { allowedImageTypes, allowedVideoTypes } from '@util/media.ts';

  // bindings
  let hiddenFileInputElem: HTMLInputElement;
  let previewDialogElem: HTMLDialogElement;

  // types
  interface Props {
    maxFilesBytes: number;
  }

  interface UploadFile {
    dataUrl: string;
    name: string;
    type: 'image' | 'video';
    size: number;
    file: File;
  }

  // inputs
  const { maxFilesBytes }: Props = $props();

  // states
  let uploadFiles = $state<UploadFile[]>([]);
  let previewUploadFile = $state<UploadFile | null>(null);

  // lifecycle
  $effect(() => {
    document.dispatchEvent(
      new CustomEvent('dropzoneInput', {
        detail: {
          files: uploadFiles.map((uf) => uf.file)
        }
      })
    );
  });

  $effect(() => {
    if (previewUploadFile) previewDialogElem.show();
  });

  // functions
  function addFiles(files: FileList) {
    for (const file of files) {
      if (uploadFiles.find((uf) => uf.name === file.name && uf.size === file.size) !== undefined) {
        continue;
      }

      let type: 'image' | 'video';
      if (allowedImageTypes.find((mime) => mime === file.type) !== undefined) {
        type = 'image';
      } else if (allowedVideoTypes.find((mime) => mime === file.type) !== undefined) {
        type = 'video';
      } else {
        $popupState = {
          type: 'error',
          title: 'Ungültige Datei',
          message:
            'Das Dateiformat wird nicht unterstützt. Nur Bilder (.png, .jpg, .jpeg, .webp, .avif) und Videos (.mp4, .webm) sind gültig'
        };
        return;
      }

      if (uploadFiles.reduce((prev, curr) => prev + curr.size, 0) + file.size > maxFilesBytes) {
        $popupState = {
          type: 'error',
          title: 'Datei zu groß',
          message: `Die Dateien dürfen insgesamt nur ${bytesToHumanReadable(maxFilesBytes)} groß sein. Fall deine Anhänge größer sind, lade sie bitte auf einem externen Filehoster hoch (z.B. file.io, Google Drive, ...) und füge den Link zum teilen der Datei(en) zu den Report Details hinzu`
        };
        return;
      }

      const reader = new FileReader();
      reader.onload = () => {
        uploadFiles.push({
          dataUrl: reader.result as string,
          name: file.name,
          type: type,
          size: file.size,
          file: file
        });
      };
      reader.readAsDataURL(file);
    }
  }

  function removeFile(file: UploadFile) {
    const index = uploadFiles.findIndex((uf) => uf.size === file.size && uf.name === file.name);
    const uploadFile = uploadFiles.splice(index, 1).pop()!;
    URL.revokeObjectURL(uploadFile.dataUrl);
  }

  function bytesToHumanReadable(bytes: number) {
    const sizes = ['B', 'KB', 'MB'];

    const i = Math.floor(Math.log(bytes) / Math.log(1024));
    const size = parseFloat((bytes / Math.pow(1024, i)).toFixed(2));

    return `${size} ${sizes[i]}`;
  }

  // callbacks
  function onAddFiles(e: Event & { currentTarget: EventTarget & HTMLInputElement }) {
    e.preventDefault();
    if ((e.target as typeof e.currentTarget).files) addFiles((e.target as typeof e.currentTarget).files!);
  }

  function onDrop(e: DragEvent) {
    e.preventDefault();
    if (e.dataTransfer) addFiles(e.dataTransfer.files);
  }

  function onFileRemove(file: UploadFile) {
    removeFile(file);
  }
</script>

<fieldset class="fieldset">
  <legend class="fieldset-legend">Anhänge</legend>
  <!-- svelte-ignore a11y_no_static_element_interactions -->
  <!-- svelte-ignore a11y_click_events_have_key_events -->
  <div
    class="h-12 rounded border border-dashed flex cursor-pointer"
    class:h-26={uploadFiles.length > 0}
    dropzone="copy"
    onclick={() => hiddenFileInputElem.click()}
    ondrop={onDrop}
    ondragover={(e) => e.preventDefault()}
  >
    {#if uploadFiles.length === 0}
      <div class="flex justify-center items-center w-full h-full">
        <p>Hier Dateien droppen oder klicken um sie hochzuladen</p>
      </div>
    {/if}
    {#each uploadFiles as uploadFile (uploadFile.name)}
      <div
        class="relative flex flex-col items-center w-22 h-22 m-1 cursor-default"
        onclick={(e) => e.stopImmediatePropagation()}
      >
        <div class="cursor-zoom-in" onclick={() => (previewUploadFile = uploadFile)}>
          {#if uploadFile.type === 'image'}
            <img src={uploadFile.dataUrl} alt={uploadFile.name} class="w-16 h-16" />
          {:else if uploadFile.type === 'video'}
            <!-- svelte-ignore a11y_media_has_caption -->
            <video src={uploadFile.dataUrl} class="w-16 h-16"></video>
          {/if}
        </div>
        <span>{bytesToHumanReadable(uploadFile.size)}</span>
        <button class="cursor-pointer" onclick={() => onFileRemove(uploadFile)}>Datei entfernen</button>
      </div>
    {/each}
  </div>
</fieldset>
<input
  bind:this={hiddenFileInputElem}
  type="file"
  multiple
  accept={[...allowedImageTypes, ...allowedVideoTypes].join(', ')}
  class="hidden absolute top-0 left-0 h-0 w-0"
  onchange={onAddFiles}
/>

<dialog class="modal" bind:this={previewDialogElem} onclose={() => setTimeout(() => (previewUploadFile = null), 300)}>
  <div class="modal-box">
    {#if previewUploadFile?.type === 'image'}
      <img src={previewUploadFile.dataUrl} alt={previewUploadFile.name} />
    {:else if previewUploadFile?.type === 'video'}
      <!-- svelte-ignore a11y_media_has_caption -->
      <video src={previewUploadFile.dataUrl} controls></video>
    {/if}
  </div>
  <form method="dialog" class="modal-backdrop bg-[rgba(0,0,0,.3)]">
    <button class="absolute top-3 right-3 btn btn-circle">✕</button>
    <button class="!cursor-default">close</button>
  </form>
</dialog>
