<script lang="ts" setup>
// @unocss-include
import type { FactorMedia } from '@factor/api'
import { log, objectId, vue } from '@factor/api'
import type { MediaDisplayObject } from './utils'
import ElSpinner from './ElSpinner.vue'

const props = defineProps({
  modelValue: {
    type: Array as vue.PropType<MediaDisplayObject[]>,
    default: () => [],
  },
  service: {
    type: Object as vue.PropType<{ factorMedia?: FactorMedia }>,
    default: () => {},
  },
  allowedFile: { type: String, default: 'PDF, PNG, JPG, GIF up to 10MB' },
})
const emit = defineEmits<{
  (event: 'update:modelValue', payload: MediaDisplayObject[]): void
}>()
// uploadId is to allow label click without conflict with others on page
const uploadId = `file-upload-${objectId()}`
const draggingOver = vue.ref()
const uploading = vue.ref(false)

async function updateValue(value: MediaDisplayObject[]): Promise<void> {
  emit('update:modelValue', value)
}

async function uploadFiles(files?: FileList | null) {
  const factorMedia = props.service.factorMedia
  if (!factorMedia)
    throw new Error('factorMedia service not added to media uploader')

  if (files) {
    log.info('mediaUpload', `uploading ${files.length} files`)
  }
  else {
    log.info('mediaUpload', 'No files to upload')
    return
  }
  uploading.value = true

  const uploads = [...files].map(file => ({
    file,
    fileId: objectId(),
    progress: () => {},
  }))

  const result = await factorMedia.uploadFiles({ uploads })
  log.info('mediaUpload', `upload result`, { data: result })

  const urls = result
    .filter(_ => _ && _.status === 'success' && _.data)
    .map(r => r?.data) as MediaDisplayObject[]

  await updateValue(urls)
  uploading.value = false
}

async function handleUploadFile(ev: Event) {
  const target = ev.target as HTMLInputElement
  await uploadFiles(target.files)
}
async function handleDropFile(ev: Event) {
  const event = ev as DragEvent
  await uploadFiles(event.dataTransfer?.files)
}
</script>

<template>
  <div
    class="media-body"
    @dragover.prevent
    @drop.prevent
  >
    <div v-if="uploading" class="p-12">
      <ElSpinner class="text-theme-200 m-auto h-12 w-12" />
    </div>
    <label
      v-else
      :for="uploadId"
      class="border-theme-300 hover:bg-theme-50 hover:border-theme-400 mt-1 flex cursor-pointer justify-center rounded-md border border-dashed p-3"
      :class="[]"
      @drop="handleDropFile"
      @dragover="draggingOver = true"
      @dragleave="draggingOver = false"
    >
      <div class="space-y-1 text-center">
        <div class="text-theme-400 flex items-center space-x-1 text-[10px]">
          <div class="i-carbon-image text-theme-300 inline-block text-lg" />
          <div class="font-medium uppercase tracking-wide">Upload Image</div>
        </div>
        <input
          :id="uploadId"
          name="file-upload"
          type="file"
          class="sr-only"
          accept="image/*"
          multiple
          @change="handleUploadFile"
        >
      </div>
    </label>
  </div>
</template>
