<template>
  <q-field
    v-model="model"
    v-bind="$attrs"
    borderless
    :rules="rules"
    :error
    :error-message
  >
    <div class="column flex-center q-mb-sm full-width">
      <span class="text-grey-6">{{ label }}</span>
      <div
        class="image-preview-container"
        :class="{
          'has-image': preview,
          'is-dragging': isDragging,
        }"
        @click="pickImage"
        @dragover.prevent="handleDragOver"
        @dragleave.prevent="handleDragLeave"
        @drop.prevent="handleDrop"
      >
        <template v-if="!preview">
          <q-icon
            :name="
              isDragging
                ? 'file_upload'
                : type == 'image'
                  ? 'add_photo_alternate'
                  : 'insert_drive_file'
            "
            size="48px"
            color="grey-6"
            class="absolute-center"
          />
          <div
            class="text-caption text-grey-6 text-center absolute-bottom q-pb-sm q-px-md"
          >
            {{
              isDragging
                ? $t("common.ui.file.drag_and_drop")
                : type == "image"
                  ? $t("common.ui.file.click_select_image")
                  : $t("common.ui.file.click_select")
            }}
          </div>
        </template>
        <q-img
          v-else-if="type == 'image'"
          :src="preview"
          fit="cover"
          class="full-height"
        >
          <div class="absolute-bottom text-right">
            <q-btn
              flat
              dense
              round
              color="negative"
              icon="delete"
              @click.stop="clearImage"
            />
          </div>
        </q-img>
        <div v-else class="position-relative column full-height flex-center">
          <q-icon name="mdi-file-check" size="48px" color="grey-6" />
          <div
            class="absolute-bottom text-caption text-grey-6 text-center q-mb-sm q-px-md"
          >
            {{ preview }}
          </div>
        </div>
      </div>

      <q-file v-show="false" ref="fileInput" v-model="model" :accept="accept" />
    </div>
  </q-field>
</template>

<script setup>
import { ref, useTemplateRef, watch } from "vue";

const { label, rules, accept, type, initialImage } = defineProps({
  label: {
    type: String,
    default: "Select Image",
  },
  rules: {
    type: Array,
    default: () => [],
  },
  accept: {
    type: String,
    default: "image/*",
  },
  type: {
    type: String,
    default: "image",
  },
  initialImage: {
    type: String,
    default: null,
  },
  error: {
    type: Boolean,
    default: false,
  },
  errorMessage: {
    type: String,
    default: "",
  },
});

const model = defineModel();
const base64File = defineModel("base64File", { type: String, default: null });
const preview = ref(initialImage);
const isDragging = ref(false);
const fileInput = useTemplateRef("fileInput");

const processFile = async (file) => {
  if (!file) {
    console.error("No file provided");
    return;
  }

  if (type == "image" && !file.type.startsWith("image/")) {
    console.error("Invalid file type");
    return;
  }

  if (type == "file") {
    const blob = new Blob([file], { type: file.type });
    preview.value = file.name;
    return new Promise((resolve) => {
      const reader = new FileReader();
      reader.onload = (e) => {
        base64File.value = e.target.result;
        console.log(preview.value);
        resolve();
      };
      reader.readAsDataURL(blob);
    });
  } else {
    return new Promise((resolve) => {
      const reader = new FileReader();
      reader.onload = (e) => {
        base64File.value = e.target.result;
        preview.value = e.target.result;
        resolve();
      };
      reader.readAsDataURL(file);
    });
  }
};

const pickImage = () => {
  fileInput.value?.pickFiles();
};

const clearImage = () => {
  model.value = null;
  preview.value = null;
};

const handleDragOver = () => {
  isDragging.value = true;
};

const handleDragLeave = () => {
  isDragging.value = false;
};

const handleDrop = async (event) => {
  isDragging.value = false;
  const file = event.dataTransfer?.files?.[0];

  if (file) {
    model.value = file;
    await processFile(file);
  }
};

watch(
  () => model.value,
  async (value, oldValue) => {
    if (value != oldValue) {
      await processFile(value);
    } else {
      preview.value = null;
    }
  },
);
</script>

<style lang="scss" scoped>
@use "sass:map";
@use "src/css/quasar.variables.scss";

.image-preview-container {
  .body--dark & {
    --image-bg-color: #{map.get($colors-dark, "surface")};
    --image-border-color: #{map.get($colors-dark, "primary")};
    --image-border-hover-color: #{map.get($colors-dark, "primary-dark")};
  }

  .body--light & {
    --image-bg-color: #{map.get($colors, "surface")};
    --image-border-color: #{map.get($colors, "primary")};
    --image-border-hover-color: #{map.get($colors, "primary-dark")};
  }

  width: 200px;
  height: 200px;
  border: 2px dashed var(--image-border-color);
  border-radius: 4px;
  position: relative;
  overflow: hidden;
  transition: all 0.3s;
  cursor: pointer;

  &.is-dragging {
    border-color: var(--image-border-hover-color);
    background-color: var(--image-bg-color);
    opacity: 0.8;
  }

  &:hover {
    border-color: var(--image-border-hover-color);
    background-color: var(--image-bg-color);
  }

  &.has-image {
    border-style: solid;
  }
}
</style>
