import { message } from 'ant-design-vue'
import FileSaver from 'file-saver'
import { useI18n } from 'vue-i18n'
import {
  ColumnInj,
  EditModeInj,
  IsPublicInj,
  MetaInj,
  NOCO,
  ReadonlyInj,
  computed,
  inject,
  isImage,
  ref,
  useApi,
  useFileDialog,
  useInjectionState,
  useProject,
  watch,
} from '#imports'
import MdiPdfBox from '~icons/mdi/pdf-box'
import MdiFileWordOutline from '~icons/mdi/file-word-outline'
import MdiFilePowerpointBox from '~icons/mdi/file-powerpoint-box'
import MdiFileExcelOutline from '~icons/mdi/file-excel-outline'
import IcOutlineInsertDriveFile from '~icons/ic/outline-insert-drive-file'

interface AttachmentProps extends File {
  data?: any
  file: File
  title: string
  mimetype: string
}

export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
  (updateModelValue: (data: string | Record<string, any>[]) => void) => {
    const isReadonly = inject(ReadonlyInj, false)

    const isPublic = inject(IsPublicInj, ref(false))

    const meta = inject(MetaInj)!

    const column = inject(ColumnInj)!

    const editEnabled = inject(EditModeInj, ref(false))

    /** keep user selected File object */
    const storedFiles = ref<AttachmentProps[]>([])

    const attachments = ref<File[]>([])

    const modalVisible = ref(false)

    const selectedImage = ref()

    const { project } = useProject()

    const { api, isLoading } = useApi()

    const { files, open } = useFileDialog()

    const { t } = useI18n()

    /** remove a file from our stored attachments (either locally stored or saved ones) */
    function removeFile(i: number) {
      if (isPublic.value) {
        storedFiles.value.splice(i, 1)

        updateModelValue(storedFiles.value.map((stored) => stored.file))
      } else {
        attachments.value.splice(i, 1)

        updateModelValue(attachments.value)
      }
    }

    /** save a file on select / drop, either locally (in-memory) or in the db */
    async function onFileSelect(selectedFiles: FileList | File[]) {
      if (!selectedFiles.length) return

      if (isPublic.value) {
        storedFiles.value.push(
          ...(await Promise.all<AttachmentProps>(
            Array.from(selectedFiles).map(
              (file) =>
                new Promise<AttachmentProps>((resolve) => {
                  const res: AttachmentProps = { ...file, file, title: file.name, mimetype: file.type }

                  if (isImage(file.name, (<any>file).mimetype ?? file.type)) {
                    const reader = new FileReader()

                    reader.onload = (e) => {
                      res.data = e.target?.result

                      resolve(res)
                    }

                    reader.onerror = () => {
                      resolve(res)
                    }

                    reader.readAsDataURL(file)
                  } else {
                    resolve(res)
                  }
                }),
            ),
          )),
        )

        return updateModelValue(storedFiles.value.map((stored) => stored.file))
      }

      const newAttachments = []

      for (const file of selectedFiles) {
        try {
          const data = await api.storage.upload(
            {
              path: [NOCO, project.value.title, meta.value.title, column.value.title].join('/'),
            },
            {
              files: file,
              json: '{}',
            },
          )

          newAttachments.push(...data)
        } catch (e: any) {
          message.error(e.message || t('msg.error.internalError'))
        }
      }

      updateModelValue([...attachments.value, ...newAttachments])
    }

    /** save files on drop */
    async function onDrop(droppedFiles: File[] | null) {
      if (droppedFiles) {
        // set files
        await onFileSelect(droppedFiles)
      }
    }

    /** download a file */
    async function downloadFile(item: Record<string, any>) {
      FileSaver.saveAs(item.url || item.data, item.title)
    }

    const FileIcon = (icon: string) => {
      switch (icon) {
        case 'mdi-pdf-box':
          return MdiPdfBox
        case 'mdi-file-word-outline':
          return MdiFileWordOutline
        case 'mdi-file-powerpoint-box':
          return MdiFilePowerpointBox
        case 'mdi-file-excel-outline':
          return MdiFileExcelOutline
        default:
          return IcOutlineInsertDriveFile
      }
    }

    /** our currently visible items, either the locally stored or the ones from db, depending on isPublicForm status */
    const visibleItems = computed<any[]>(() => (isPublic.value ? storedFiles.value : attachments.value))

    watch(files, (nextFiles) => nextFiles && onFileSelect(nextFiles))

    return {
      attachments,
      visibleItems,
      isPublic,
      isReadonly,
      meta,
      column,
      editEnabled,
      isLoading,
      api,
      open: () => open(),
      onDrop,
      modalVisible,
      FileIcon,
      removeFile,
      downloadFile,
      updateModelValue,
      selectedImage,
      storedFiles,
    }
  },
  'useAttachmentCell',
)
