<!--
Assistant de création d'image
https://norserium.github.io/vue-advanced-cropper/
-->
<template>
    <LazyLayoutDialog :show="true">
      <template #dialogType>{{ $t('image_assistant') }}</template>
      <template #dialogTitle>{{ $t('modif_picture') }}</template>
      <template #dialogText>
        <div class="upload">
          <v-row
            v-if="fetchState.pending"
            class="fill-height ma-0 loading"
            align="center"
            justify="center"
          >
            <v-progress-circular
              :indeterminate="true"
              color="neutral">
            </v-progress-circular>
          </v-row>

          <div v-else >
            <div class="upload__cropper-wrapper">
              <cropper
                ref="cropper"
                class="upload__cropper"
                check-orientation
                :src="image.src"
                :default-position="{left : coordinates.left, top : coordinates.top}"
                :default-size="coordinates.width ? {width : coordinates.width, height : coordinates.height}: defaultSize"
                @change="onChange"
              />
              <div v-if="image.src" class="upload__reset-button" title="Reset Image" @click="reset()">
                <v-icon>mdi-delete</v-icon>
              </div>
            </div>
            <div class="upload__buttons-wrapper">
              <button class="upload__button" @click="$refs.file.click()">
                <input ref="file" type="file" accept="image/*" @change="uploadImage($event)" />
                {{$t('upload_image')}}
              </button>
            </div>
          </div>

        </div>
      </template>
      <template #dialogBtn>
        <v-btn class="mr-4 submitBtn theme-neutral-strong" @click="$emit('close')">
          {{ $t('cancel') }}
        </v-btn>
        <v-btn class="mr-4 submitBtn theme-danger" @click="save">
          {{ $t('save') }}
        </v-btn>
      </template>
    </LazyLayoutDialog>

</template>

<script setup lang="ts">

import {useNuxtApp} from "#app";
import {ref, Ref} from "@vue/reactivity";
import File from '~/models/Core/File'
import {useAp2iRequestService} from "~/composables/data/useAp2iRequestService";
import UrlUtils from "~/services/utils/urlUtils";
import {useImageFetch} from "~/composables/data/useImageFetch";
import {onUnmounted, watch, WatchStopHandle} from "@vue/runtime-core";
import {useEntityManager} from "~/composables/data/useEntityManager";
import {AnyJson} from "~/types/data";

const props = defineProps({
  imageId: {
    type: Number,
    required: false
  },
  ownerId: {
    type: Number,
    required: false
  },
  field: {
    type: String,
    required: true
  }
})

const { emit } = useNuxtApp()

const { em } = useEntityManager()

const file = new File()

const cropper: Ref<any> = ref(null)

const image: Ref<AnyJson> = ref({
  id: null,
  src: null,
  file: null,
  name: null
})

const coordinates: Ref<AnyJson> = ref({})

const defaultSize = ({ imageSize, visibleArea }: any) => {
  return {
    width: (visibleArea || imageSize).width,
    height: (visibleArea || imageSize).height,
  };
}

// Si l'id est renseigné, on récupère l'Item File afin d'avoir les informations de config, le nom, etc.
if (props.imageId && props.imageId > 0) {
  const { apiRequestService } = useAp2iRequestService()
  const result: any = await apiRequestService.get(UrlUtils.join('api/files', '' + props.imageId))

  const config = JSON.parse(result.data.config)
  coordinates.value.left = config.x
  coordinates.value.top = config.y
  coordinates.value.height = config.height
  coordinates.value.width = config.width
  image.value.name = result.data.name
  image.value.id = result.data.id
}

//On récupère l'image...
const { fetch } = useImageFetch()
const { data: imageLoaded, pending } = fetch(props.imageId ?? null)

const unwatch: WatchStopHandle = watch(
  imageLoaded,
(newValue, oldValue) => {
    if (newValue === oldValue || typeof newValue === 'undefined') {
      return
    }
    image.value.src = newValue
  }
)

/**
 * Quand l'utilisateur choisit une image sur sa machine
 * @param event
 */
const uploadImage = (event:any) => {
  const { files } = event.target
  if (files && files[0]) {
    reset()
    image.value.name = files[0].name
    image.value.src = URL.createObjectURL(files[0])
    image.value.file = files[0]
  }
}

/**
 * Lorsque le cropper change de position / taille, on met à jour les coordonnées
 * @param config
 */
const onChange = ({ coordinates: config } : any) => {
  coordinates.value = config;
}

/**
 * Lorsque l'on sauvegarde l'image
 */
// TODO: Voir si tout ou partie de cette fonction peut passer dans le useImageFetch, imageManager ou imageUtils
const save = async () => {
  file.config = JSON.stringify({
    x: coordinates.value.left,
    y: coordinates.value.top,
    height: coordinates.value.height,
    width: coordinates.value.width
  })

  if (image.value.id > 0) {
    // Mise à jour d'une image existante : on bouge simplement le cropper

    file.id = image.value.id as number

    await em.persist(File, file) // TODO: à revoir

    // On émet un évent afin de mettre à jour le formulaire de départ
    emit('reload')

  } else {
    // Création d'une nouvelle image
    if (image.value.file) {

      // On créé l'objet File à sauvegarder
      file.name = image.value.name
      file.imgFieldName = props.field
      file.visibility = 'EVERYBODY'
      file.folder = 'IMAGES'
      file.status = 'READY'

      if (props.ownerId) {
        file.ownerId = props.ownerId
      }

      const returnedFile = await em.persist(File, file) // TODO: à revoir, il faudra pouvoir passer `image.value.file` avec la requête

      //On émet un évent afin de mettre à jour le formulaire de départ
      emit('update', returnedFile.data['@id'])

    } else {
      // On reset l'image : on a appuyé sur "poubelle" puis on enregistre
      emit('reset')
    }
  }
}

/**
 * On choisit de supprimer l'image présente
 */
const reset = () => {
  image.value.src = null
  image.value.file = null
  image.value.name = null
  image.value.id = null
  URL.revokeObjectURL(image.value.src)
}

/**
 * Lorsqu'on démonte le component on supprime le watcher et on revoke l'objet URL
 */
onUnmounted(() => {
  unwatch()
    if (image.value.src) {
      URL.revokeObjectURL(image.value.src)
    }
})
</script>

<style lang="scss">
  .vue-advanced-cropper__stretcher{
    height: auto !important;
    width: auto !important;
  }
  .loading{
    height: 300px;
  }
  .upload {
    user-select: none;
    padding: 20px;
    display: block;
    &__cropper {
       border: solid 1px rgb(var(--v-theme-on-neutral-strong));;
       min-height: 500px;
       max-height: 500px;
     }
    &__cropper-wrapper {
       position: relative;
     }
    &__reset-button {
      position: absolute;
      right: 20px;
      bottom: 20px;
      cursor: pointer;
      display: flex;
      align-items: center;
      justify-content: center;
      height: 42px;
      width: 42px;
      background: rgb(var(--v-theme-neutral));
      transition: background 0.5s;
      &:hover {
        background: rgb(var(--v-theme-primary-alt));
      }
    }
    &__buttons-wrapper {
       display: flex;
       justify-content: center;
       margin-top: 17px;
     }
    &__button {
       border: none;
       outline: solid transparent;
       color: rgb(var(--v-theme-on-neutral));
       font-size: 16px;
       padding: 10px 20px;
       background: rgb(var(--v-theme-neutral));
       cursor: pointer;
       transition: background 0.5s;
       margin: 0 16px;
      &:hover,
      &:focus {
         background: rgb(var(--v-theme-primary-alt));
       }
      input {
        display: none;
      }
    }
  }
</style>
