import { computed, defineComponent, onBeforeUnmount, onMounted, ref } from 'vue';
import type { ExtractPropTypes, PropType, CSSProperties } from 'vue';
import EyeOutlined from '@ant-design/icons-vue/EyeOutlined';
import DeleteOutlined from '@ant-design/icons-vue/DeleteOutlined';
import DownloadOutlined from '@ant-design/icons-vue/DownloadOutlined';
import Tooltip from '../../tooltip';
import Progress from '../../progress';

import type {
  ItemRender,
  UploadFile,
  UploadListProgressProps,
  UploadListType,
  UploadLocale,
} from '../interface';
import type { VueNode } from '../../_util/type';
import useConfigInject from '../../_util/hooks/useConfigInject';
import Transition, { getTransitionProps } from '../../_util/transition';
export const listItemProps = () => {
  return {
    prefixCls: String,
    locale: { type: Object as PropType<UploadLocale>, default: undefined as UploadLocale },
    file: Object as PropType<UploadFile>,
    items: Array as PropType<UploadFile[]>,
    listType: String as PropType<UploadListType>,
    isImgUrl: Function as PropType<(file: UploadFile) => boolean>,

    showRemoveIcon: { type: Boolean, default: undefined },
    showDownloadIcon: { type: Boolean, default: undefined },
    showPreviewIcon: { type: Boolean, default: undefined },
    removeIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
    downloadIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
    previewIcon: Function as PropType<(opt: { file: UploadFile }) => VueNode>,

    iconRender: Function as PropType<(opt: { file: UploadFile }) => VueNode>,
    actionIconRender: Function as PropType<
      (opt: {
        customIcon: VueNode;
        callback: () => void;
        prefixCls: string;
        title?: string | undefined;
      }) => VueNode
    >,
    itemRender: Function as PropType<ItemRender>,
    onPreview: Function as PropType<(file: UploadFile, e: Event) => void>,
    onClose: Function as PropType<(file: UploadFile) => void>,
    onDownload: Function as PropType<(file: UploadFile) => void>,
    progress: Object as PropType<UploadListProgressProps>,
  };
};

export type ListItemProps = Partial<ExtractPropTypes<ReturnType<typeof listItemProps>>>;

export default defineComponent({
  name: 'ListItem',
  inheritAttrs: false,
  props: listItemProps(),
  setup(props, { slots, attrs }) {
    const showProgress = ref(false);
    const progressRafRef = ref();
    onMounted(() => {
      progressRafRef.value = setTimeout(() => {
        showProgress.value = true;
      }, 300);
    });
    onBeforeUnmount(() => {
      clearTimeout(progressRafRef.value);
    });
    const { rootPrefixCls } = useConfigInject('upload', props);
    const transitionProps = computed(() => getTransitionProps(`${rootPrefixCls.value}-fade`));
    return () => {
      const {
        prefixCls,
        locale,
        listType,
        file,
        items,
        progress: progressProps,
        iconRender = slots.iconRender,
        actionIconRender = slots.actionIconRender,
        itemRender = slots.itemRender,
        isImgUrl,
        showPreviewIcon,
        showRemoveIcon,
        showDownloadIcon,
        previewIcon: customPreviewIcon = slots.previewIcon,
        removeIcon: customRemoveIcon = slots.removeIcon,
        downloadIcon: customDownloadIcon = slots.downloadIcon,
        onPreview,
        onDownload,
        onClose,
      } = props;
      const { class: className, style } = attrs;
      // This is used for legacy span make scrollHeight the wrong value.
      // We will force these to be `display: block` with non `picture-card`
      const spanClassName = `${prefixCls}-span`;

      const iconNode = iconRender({ file });
      let icon = <div class={`${prefixCls}-text-icon`}>{iconNode}</div>;
      if (listType === 'picture' || listType === 'picture-card') {
        if (file.status === 'uploading' || (!file.thumbUrl && !file.url)) {
          const uploadingClassName = {
            [`${prefixCls}-list-item-thumbnail`]: true,
            [`${prefixCls}-list-item-file`]: file.status !== 'uploading',
          };
          icon = <div class={uploadingClassName}>{iconNode}</div>;
        } else {
          const thumbnail = isImgUrl?.(file) ? (
            <img
              src={file.thumbUrl || file.url}
              alt={file.name}
              class={`${prefixCls}-list-item-image`}
            />
          ) : (
            iconNode
          );
          const aClassName = {
            [`${prefixCls}-list-item-thumbnail`]: true,
            [`${prefixCls}-list-item-file`]: isImgUrl && !isImgUrl(file),
          };
          icon = (
            <a
              class={aClassName}
              onClick={e => onPreview(file, e)}
              href={file.url || file.thumbUrl}
              target="_blank"
              rel="noopener noreferrer"
            >
              {thumbnail}
            </a>
          );
        }
      }

      const infoUploadingClass = {
        [`${prefixCls}-list-item`]: true,
        [`${prefixCls}-list-item-${file.status}`]: true,
        [`${prefixCls}-list-item-list-type-${listType}`]: true,
      };
      const linkProps =
        typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;

      const removeIcon = showRemoveIcon
        ? actionIconRender({
            customIcon: customRemoveIcon ? customRemoveIcon({ file }) : <DeleteOutlined />,
            callback: () => onClose(file),
            prefixCls,
            title: locale.removeFile,
          })
        : null;
      const downloadIcon =
        showDownloadIcon && file.status === 'done'
          ? actionIconRender({
              customIcon: customDownloadIcon ? customDownloadIcon({ file }) : <DownloadOutlined />,
              callback: () => onDownload(file),
              prefixCls,
              title: locale.downloadFile,
            })
          : null;
      const downloadOrDelete = listType !== 'picture-card' && (
        <span
          key="download-delete"
          class={[
            `${prefixCls}-list-item-card-actions`,
            {
              picture: listType === 'picture',
            },
          ]}
        >
          {downloadIcon}
          {removeIcon}
        </span>
      );
      const listItemNameClass = `${prefixCls}-list-item-name`;
      const preview = file.url
        ? [
            <a
              key="view"
              target="_blank"
              rel="noopener noreferrer"
              class={listItemNameClass}
              title={file.name}
              {...linkProps}
              href={file.url}
              onClick={e => onPreview(file, e)}
            >
              {file.name}
            </a>,
            downloadOrDelete,
          ]
        : [
            <span
              key="view"
              class={listItemNameClass}
              onClick={e => onPreview(file, e)}
              title={file.name}
            >
              {file.name}
            </span>,
            downloadOrDelete,
          ];
      const previewStyle: CSSProperties = {
        pointerEvents: 'none',
        opacity: 0.5,
      };
      const previewIcon = showPreviewIcon ? (
        <a
          href={file.url || file.thumbUrl}
          target="_blank"
          rel="noopener noreferrer"
          style={file.url || file.thumbUrl ? undefined : previewStyle}
          onClick={e => onPreview(file, e)}
          title={locale.previewFile}
        >
          {customPreviewIcon ? customPreviewIcon({ file }) : <EyeOutlined />}
        </a>
      ) : null;

      const actions = listType === 'picture-card' && file.status !== 'uploading' && (
        <span class={`${prefixCls}-list-item-actions`}>
          {previewIcon}
          {file.status === 'done' && downloadIcon}
          {removeIcon}
        </span>
      );

      let message;
      if (file.response && typeof file.response === 'string') {
        message = file.response;
      } else {
        message = file.error?.statusText || file.error?.message || locale.uploadError;
      }
      const iconAndPreview = (
        <span class={spanClassName}>
          {icon}
          {preview}
        </span>
      );

      const dom = (
        <div class={infoUploadingClass}>
          <div class={`${prefixCls}-list-item-info`}>{iconAndPreview}</div>
          {actions}
          {showProgress.value && (
            <Transition {...transitionProps.value}>
              <div v-show={file.status === 'uploading'} class={`${prefixCls}-list-item-progress`}>
                {'percent' in file ? (
                  <Progress {...progressProps} type="line" percent={file.percent} />
                ) : null}
              </div>
            </Transition>
          )}
        </div>
      );
      const listContainerNameClass = {
        [`${prefixCls}-list-${listType}-container`]: true,
        [`${className}`]: !!className,
      };
      const item =
        file.status === 'error' ? (
          <Tooltip title={message} getPopupContainer={node => node.parentNode as HTMLElement}>
            {dom}
          </Tooltip>
        ) : (
          dom
        );

      return (
        <div class={listContainerNameClass} style={style} ref={ref}>
          {itemRender
            ? itemRender({
                originNode: item,
                file,
                fileList: items,
                actions: {
                  download: onDownload.bind(null, file),
                  preview: onPreview.bind(null, file),
                  remove: onClose.bind(null, file),
                },
              })
            : item}
        </div>
      );
    };
  },
});
