import classNames from 'classnames'
import { FC, useMemo } from 'react'

import { isImageFileLike, mergeFilesAndTransfers } from 'shared-utils/fileupload'

import { useImagePreview, useOperationState } from './hooks'
import { buildOperationContext, getProgressState, QueueItemContent } from './QueueItemContent'
import { FilenameRenderer, ImagePreviewModal, ThumbnailRenderer } from './Subcomponents'
import { TruncateContext } from './Truncate'
import {
  TFileAndTransfer,
  TFileId,
  TFileItemList,
  TFileTransfer,
  TItemRenderer,
  TQueueItemOperation,
  TQueueOperationContext,
} from './types'

const useFilesAndTransfers = (
  files: TFileItemList,
  transfers: TFileTransfer[],
  uploadStrategy: 'form' | 'custom',
): TFileAndTransfer[] =>
  useMemo(
    () => mergeFilesAndTransfers(files, transfers, uploadStrategy) as TFileAndTransfer[],
    [files, transfers, uploadStrategy],
  )

/** Returns only uploaded images (used for the preview modal). */
const usePreviewableImages = (filesAndTransfers: TFileAndTransfer[], enabled: boolean): TFileAndTransfer[] =>
  useMemo(() => {
    if (!enabled) return []
    return filesAndTransfers.filter((item) => item.progress === 'done' && isImageFileLike(item))
  }, [filesAndTransfers, enabled])

interface IQueueDisplay {
  cancelTransfer: (fileItemId: string) => void
  transfers?: TFileTransfer[]
  files: TFileItemList
  queueItemOperations?: TQueueItemOperation[]
  ItemRenderer?: TItemRenderer
  truncateTail?: number
  enableImagePreview?: boolean
  uploadStrategy?: 'form' | 'custom'
  disabled?: boolean
  inputName: string
  buildAttributeAccessors: (fileId: TFileId) => Pick<TQueueOperationContext, 'getAttribute' | 'setAttribute'>
}

export const QueueDisplay: FC<IQueueDisplay> = ({
  files,
  cancelTransfer,
  transfers = [],
  queueItemOperations = [],
  ItemRenderer = FilenameRenderer,
  truncateTail,
  enableImagePreview = false,
  uploadStrategy = 'form',
  disabled = false,
  inputName,
  buildAttributeAccessors,
}) => {
  const filesAndTransfers = useFilesAndTransfers(files, transfers, uploadStrategy)
  const previewableImages = usePreviewableImages(filesAndTransfers, enableImagePreview)

  const operationState = useOperationState(queueItemOperations)
  const preview = useImagePreview(previewableImages)

  return (
    <>
      <ul className="pkt-fileupload__queue-display">
        <TruncateContext.Provider value={{ tail: truncateTail }}>
          {filesAndTransfers.map((transferItem) => {
            const activatedOperation = operationState.getActivated(transferItem.fileId)
            const commonContentProps = {
              transferItem,
              operations: queueItemOperations,
              activatedOperation,
              inputName,
              disabled,
              onActivate: operationState.activate,
              onClose: operationState.close,
              buildAttributeAccessors,
            }

            return (
              <li
                key={transferItem.fileId}
                className={classNames('pkt-fileupload__queue-display__item', {
                  'pkt-fileupload__queue-display__item--in-progress': typeof transferItem.progress === 'number',
                  [`pkt-fileupload__queue-display__item--${transferItem.progress}`]:
                    typeof transferItem.progress === 'string',
                })}
              >
                {/* Hidden inputs for form submission */}
                {queueItemOperations
                  .filter((op) => op.renderHidden)
                  .map((operation) => (
                    <span key={`${operation.id}-${transferItem.fileId}`}>
                      {operation.renderHidden!(
                        buildOperationContext({ operation, ...commonContentProps }),
                      )}
                    </span>
                  ))}

                <QueueItemContent
                  {...commonContentProps}
                  ItemRenderer={ItemRenderer}
                  enableImagePreview={enableImagePreview}
                  onCancelTransfer={cancelTransfer}
                  onOpenPreview={preview.open}
                />
              </li>
            )
          })}
        </TruncateContext.Provider>
      </ul>

      {enableImagePreview && previewableImages.length > 0 && (
        <ImagePreviewModal
          modalRef={preview.modalRef}
          isOpen={preview.isOpen}
          images={previewableImages}
          currentIndex={preview.currentIndex}
          onClose={preview.close}
          onNavigate={preview.navigate}
        />
      )}
    </>
  )
}

export { getProgressState } // preserved for backwards import compatibility

export const ItemRenderers: Record<string, TItemRenderer> = {
  filename: FilenameRenderer,
  thumbnail: ThumbnailRenderer,
}
