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

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

const isImageFile = (item: TFileAndTransfer): boolean => {
  if (item.file.type?.startsWith('image/')) return true
  return /\.(jpe?g|png|gif|webp|heic|heif|bmp|svg)$/i.test(item.file.name || '')
}

// ============================================
// Helper: Transform files with transfer status
// ============================================

/**
 * Combine `files` with their transfer state (`transfers`) and sort by priority.
 *
 * Sort order:
 * - in-progress first
 * - then errors
 * - then everything else
 */
const useFilesAndTransfers = (
  files: TFileItemList,
  transfers: TFileTransfer[],
  uploadStrategy: 'form' | 'custom',
): TFileAndTransfer[] => {
  return useMemo(() => {
    const mapped = files.map((fileItem: FileItem) => {
      const transfer = transfers.find((t) => t.fileId === fileItem.fileId)
      return {
        ...fileItem,
        progress: transfer?.progress ?? (uploadStrategy === 'form' ? 'done' : 'queued'),
        errorMessage: transfer?.errorMessage,
        showProgress: transfer?.showProgress,
        lastProgress: transfer?.lastProgress,
      }
    })

    // Sort order: in-progress first, then errors, then the rest
    const priority = { 'in-progress': 0, error: 1, idle: 2 } as const
    return mapped.sort((a, b) => priority[getProgressState(a.progress)] - priority[getProgressState(b.progress)])
  }, [files, transfers, uploadStrategy])
}

// ============================================
// Helper: Filter previewable images
// ============================================

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

// ============================================
// QueueDisplay Props
// ============================================

/**
 * Queue list renderer for `PktFileUpload`.
 *
 * This component is UI-only; state changes are handled via callbacks / operations passed in.
 */
interface IQueueDisplay {
  /** Called when the user cancels/removes a file (also used to cancel transfers). */
  cancelTransfer: (fileItemId: string) => void
  /** Transfer states used for `uploadStrategy="custom"`. */
  transfers?: TFileTransfer[]
  /** Current file items. */
  files: TFileItemList
  /** Operations (rename/comment/remove/etc) rendered per queue item. */
  queueItemOperations?: TQueueItemOperation[]
  /** Custom renderer for each queue item (defaults to filename renderer). */
  ItemRenderer?: TItemRenderer
  /** Number of trailing characters to keep when truncating long filenames. */
  truncateTail?: number
  /** Enable image preview modal (only affects thumbnail view). */
  enableImagePreview?: boolean
  /** Upload mode decides default queue state when no transfer exists. */
  uploadStrategy?: 'form' | 'custom'
}

// ============================================
// QueueDisplay Component
// ============================================

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

  // State management
  const operationState = useOperationState(queueItemOperations)
  const preview = useImagePreview(previewableImages)

  return (
    <>
      <ul className="pkt-fileupload__queue-display">
        <TruncateContext.Provider value={{ tail: truncateTail }}>
          {filesAndTransfers.map((transferItem) => (
            <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((op) => op.renderHidden!(transferItem))}

              {/* Main content based on state */}
              <QueueItemContent
                transferItem={transferItem}
                activatedOperation={operationState.getActivated(transferItem.fileId)}
                operations={queueItemOperations}
                ItemRenderer={ItemRenderer}
                enableImagePreview={enableImagePreview}
                onActivate={operationState.activate}
                onClose={operationState.close}
                onCancelTransfer={cancelTransfer}
                onOpenPreview={preview.open}
              />
            </li>
          ))}
        </TruncateContext.Provider>
      </ul>

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

// ============================================
// ItemRenderers Export
// ============================================

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