import {
  computed, defineComponent,
  type PropType, ref,
} from 'vue'
import type ApiInterface from '../../types/api-interface'
import { ArkUiConstants } from '../../composables/use-ark-ui'
import { type FileData } from './upload-area-types'
import './assets/styles.scss'

export const useUploadFile = async (params: { api?: ApiInterface, endpoint: string, file: File }) => {
  const api = params.api || ArkUiConstants.api
  const endpoint = params.endpoint || '/file/'
  if (!api) {
    throw new Error('API is not defined')
  }

  try {
    const data = new FormData()
    data.append('file', params.file)
    return (await api.post(endpoint, data)).data
  } catch (e) {
    throw new Error('File upload error')
  }
}

/**
 * Кнопка для загрузки файлов. Имеет настраиваемый размер.
 * <p>
 *   <a href="https://www.figma.com/file/Q4Z4CnFx4i0qhD5fbgnPpf/%F0%9F%92%BB-%D0%94%D0%B8%D0%B7%D0%B0%D0%B9%D0%BD-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0-ARK-SPACE?type=design&node-id=6288%3A142020&mode=dev" target="_blank">Дизайн</a>
 * </p>
 */
export default defineComponent({
  props: {
    /**
     * Настройка доступности файла, даже если компонент заблокирован
     */
    isFileAvailable: {
      type: Boolean,
      default: false,
    },

    /**
     * Состояние лоадера в кнопке
     */
    isLoading: {
      type: Boolean,
      default: false,
    },

    /**
     * Объект ApiInterface.
     */
    api: {
      type: Object as PropType<ApiInterface>,
      required: true,
    },
    /**
     * Строка - конечная точка API (по умолчанию '/file/').
     */
    endpoint: {
      type: String,
      default: '/file/',
    },
    /**
     * Загружаемый файл.
     */
    file: {
      type: [Object, null] as PropType<FileData|null>,
      default: null,
    },
    /**
     * Массив строк с допустимыми форматами файлов.
     * По умолчанию ['.jpg', '.png', '.pdf'].
     */
    formats: {
      type: Array as PropType<string[]>,
      default: () => ['.jpg', '.png', '.pdf'],
    },
    /**
     * Максимальный вес файла \
     * Указывается в килобайтах \
     * 1024 = 1мб
     */
    maxFileSize: {
      type: Number,
      default: undefined,
    },
    /**
     * Функция, вызываемая при загрузке файла.
     */
    onUpload: {
      type: Function as PropType<(file: FileData|null) => void>,
      required: true,
    },

    /**
     * Позволяет назначить пользовательскую логику удаления, включая сам запрос
     */
    onDelete: {
      type: Function as PropType<(file: FileData | null) => void>,
      default: undefined,
    },

    /**
     * Размер кнопки, по умолчанию 'M'.
     */
    size: {
      type: String,
      default: 'M',
    },
    /**
     * Флаг отключена ли кнопка.
     */
    isDisabled: {
      type: Boolean,
      default: false,
    },
    /**
     * Кастомная ширина кнопки в px.
     */
    width: {
      type: String,
      default: null,
    },

    label: {
      type: String,
      default: 'Загрузить файл',
    },
  },

  setup(props) {
    const isLoading = ref(false)

    const errorText = ref<undefined | string>(undefined)
    const isError = computed(() => typeof errorText.value !== 'undefined')

    const filenameWithoutExtension = computed(() => {
      if (!props.file) return undefined

      const { name, extension } = props.file
      const lastDotIndex = name.lastIndexOf('.')

      if (lastDotIndex !== -1) {
        const maybeExtension = name.substring(lastDotIndex + 1)

        if (maybeExtension === extension) {
          return name.substring(0, lastDotIndex)
        }
      }

      return name
    })

    const upload = (value: FileData | null) => {
      if (props.onUpload) {
        props.onUpload(value)
      }
    }
    const onChange = (e: Event) => {
      const { files } = e.target as HTMLInputElement

      if (files && files.length) {
        isLoading.value = true

        if (props.maxFileSize) {
          const kb = files[0].size / 1024

          if (kb > props.maxFileSize) {
            errorText.value = `Ошибка загрузки, максимальный размер файла превышает ${formatFileSize(props.maxFileSize)}`
            isLoading.value = false

            upload(null)
            return
          }
        }

        useUploadFile({ file: files[0], api: props.api, endpoint: props.endpoint })
          .then(upload)
          .catch((e) => {
            errorText.value = 'Ошибка загрузки'
            upload(null)
            throw new Error(e)
          })
          .finally(() => {
            isLoading.value = false
          })
      }
    }

    const removeFile = () => {
      if (props.file) {
        if (props.onDelete) props.onDelete(props.file)
        else props.api.delete(props.endpoint + props.file.id)
      }

      if (props.onUpload) props.onUpload(null)

      upload(null)
    }

    const reloadFile = () => {
      if (props.onUpload) props.onUpload(null)

      errorText.value = undefined
      upload(null)
    }

    function formatFileSize(kb: number) {
      if (kb < 1024) return `${kb}кб`

      let i = -1
      const units = ['мб', 'гб', 'тб']

      do {
        kb /= 1024
        i++
      } while (kb >= 1024)

      return `${Math.floor(kb)}${units[i]}`
    }

    return () => (
      <>
        <button
          class={`ark-ui-button ark-ui-upload-button ${props.size.toLowerCase()} ${props.isDisabled && props.isFileAvailable ? 'fileAvailable' : ''}`}
          style={`${(props.size.toLowerCase() === 'm' && !props.width) ? '--width: 183px' : ''}
          ${(props.size.toLowerCase() === 's' && !props.width) ? '--width: 160px' : ''}
          ${props.width ? `--width: ${props.width};` : ''}`}
          disabled={props.isDisabled}
        >
          { ((isLoading.value && !props.file) || props.isLoading)
            && <div class="loading">
              <div class="ark-ui-upload-button-icon" />
              <span class='ark-ui-button-label'>Идет загрузка...</span>
            </div> }

          { !props.file && !props.isLoading && !isError.value && !isLoading.value
            && <>
              <span class='ark-ui-button-label'>{props.label}</span>
              <input
                type="file"
                accept={props.formats.join(',')}
                onChange={onChange}
              />
            </> }

          { props.file && !props.isLoading && !isError.value && !isLoading.value
            && <div class="success">
              <a class="ark-ui-upload-file" href={props.file.file} target="_blank">
                <span
                  class='ark-ui-button-label'
                  style={`--tooltip: '${filenameWithoutExtension.value}.${props.file.extension}';`}
                >
                  {props.file.name}
                </span>
              </a>
              <button
                class="ark-ui-upload-button-icon"
                onClick={removeFile}
                style="--tooltip: 'Удалить файл';"
              />
            </div> }

          { isError.value
            && <div class="error">
              <span class='ark-ui-button-label'>{ errorText.value }</span>
              <button
                class="ark-ui-upload-button-icon"
                onClick={reloadFile}
                style="--tooltip: 'Перезагрузить файл';"
              >
                <input
                  type="file"
                  accept={props.formats.join(',')}
                  onChange={onChange}
                />
              </button>
            </div> }
        </button>

        { props.maxFileSize && !isError.value && !props.file ? <div class="ark-ui-upload-button-description">Максимальный размер файла: {formatFileSize(props.maxFileSize)}</div> : '' }
      </>
    )
  },
})
