import { FC } from 'react'

import {
  getProgressState as sharedGetProgressState,
  isImageFileLike,
  type TProgressState,
} from 'shared-utils/fileupload'

import { PktIcon } from '../icon/Icon'
import { OperationButton, TransferError, TransferInProgress } from './Subcomponents'
import {
  TFileAndTransfer,
  TFileId,
  TItemRenderer,
  TQueueItemOperation,
  TQueueOperationContext,
  TTransferItemInProgress,
} from './types'

/**
 * Re-export so that external consumers who imported `getProgressState` from
 * this module keep working. Internal code should prefer the shared import.
 */
export const getProgressState = (progress: TFileAndTransfer['progress']): TProgressState =>
  sharedGetProgressState(progress)

/** Build a stable `TQueueOperationContext` for the given file + operation pair. */
export const buildOperationContext = ({
  operation,
  transferItem,
  inputName,
  disabled,
  activatedOperation,
  onActivate,
  onClose,
  buildAttributeAccessors,
}: {
  operation: TQueueItemOperation
  transferItem: TFileAndTransfer
  inputName: string
  disabled: boolean
  activatedOperation?: TQueueItemOperation
  onActivate: (fileId: TFileId, operation: TQueueItemOperation) => void
  onClose: (fileId: TFileId) => void
  buildAttributeAccessors: (fileId: TFileId) => Pick<TQueueOperationContext, 'getAttribute' | 'setAttribute'>
}): TQueueOperationContext => {
  const accessors = buildAttributeAccessors(transferItem.fileId)
  return {
    file: transferItem,
    inputName,
    disabled,
    isActive: activatedOperation?.id === operation.id,
    activate: () => onActivate(transferItem.fileId, operation),
    close: () => onClose(transferItem.fileId),
    getAttribute: accessors.getAttribute,
    setAttribute: accessors.setAttribute,
  }
}

interface ICommonContentProps {
  transferItem: TFileAndTransfer
  operations: TQueueItemOperation[]
  activatedOperation?: TQueueItemOperation
  inputName: string
  disabled: boolean
  onActivate: (fileId: TFileId, operation: TQueueItemOperation) => void
  onClose: (fileId: TFileId) => void
  buildAttributeAccessors: (fileId: TFileId) => Pick<TQueueOperationContext, 'getAttribute' | 'setAttribute'>
}

const buildContextsForOperations = (
  operations: TQueueItemOperation[],
  props: ICommonContentProps,
): Array<{ operation: TQueueItemOperation; context: TQueueOperationContext }> =>
  operations.map((operation) => ({
    operation,
    context: buildOperationContext({ operation, ...props }),
  }))

export const OperationActions: FC<ICommonContentProps> = (props) => {
  const contexts = buildContextsForOperations(props.operations, props)
  return (
    <div className="pkt-fileupload__queue-display__item__actions">
      {contexts
        .filter(({ operation }) => operation.id !== props.activatedOperation?.id)
        .map(({ operation, context }) => (
          <OperationButton key={operation.id} operation={operation} context={context} />
        ))}
    </div>
  )
}

export const OperationContents: FC<ICommonContentProps> = (props) => {
  const contexts = buildContextsForOperations(props.operations, props)
  return (
    <>
      {contexts
        .filter(({ operation }) => operation.renderContent)
        .map(({ operation, context }) => (
          <div className="pkt-fileupload__queue-display__item__operation-content" key={operation.id}>
            {operation.renderContent!(context)}
          </div>
        ))}
    </>
  )
}

interface IIdleStateContent extends ICommonContentProps {
  ItemRenderer: TItemRenderer
  onPreviewClick?: () => void
}

export const IdleStateContent: FC<IIdleStateContent> = (props) => {
  const { transferItem, activatedOperation, operations, ItemRenderer, onPreviewClick } = props
  const activeContext = activatedOperation
    ? buildOperationContext({ operation: activatedOperation, ...props })
    : undefined

  // When any operation UI is active (rename inline or comments extended), hide all action buttons.
  const hasOperationUIActive = activatedOperation?.renderInlineUI || activatedOperation?.renderExtendedUI
  const visibleOperations = hasOperationUIActive ? [] : operations

  return (
    <>
      {activatedOperation?.renderInlineUI && activeContext ? (
        <>
          <PktIcon name="document-text" className="pkt-fileupload__queue-display__item__icon" />
          <div className="pkt-fileupload__queue-display__item__inline-ui">
            {activatedOperation.renderInlineUI(activeContext)}
          </div>
        </>
      ) : (
        <ItemRenderer transferItem={transferItem} queueItemOperations={operations} onPreviewClick={onPreviewClick} />
      )}

      {visibleOperations.length > 0 && (
        <OperationActions {...props} operations={visibleOperations} />
      )}

      <OperationContents {...props} />

      {activatedOperation?.renderExtendedUI && activeContext && (
        <div className="pkt-fileupload__queue-display__item__expanded-operation-ui">
          {activatedOperation.renderExtendedUI(activeContext)}
        </div>
      )}
    </>
  )
}

interface IQueueItemContent extends ICommonContentProps {
  ItemRenderer: TItemRenderer
  enableImagePreview: boolean
  onCancelTransfer: (fileId: string) => void
  onOpenPreview: (fileId: TFileId) => void
}

export const QueueItemContent: FC<IQueueItemContent> = (props) => {
  const { transferItem, enableImagePreview, onCancelTransfer, onOpenPreview, disabled } = props
  const state = sharedGetProgressState(transferItem.progress)
  const isPreviewable = enableImagePreview && transferItem.progress === 'done' && isImageFileLike(transferItem)

  switch (state) {
    case 'in-progress':
      return (
        <TransferInProgress
          transferItem={transferItem as TTransferItemInProgress}
          cancelTransfer={() => onCancelTransfer(transferItem.fileId)}
          disabled={disabled}
        />
      )
    case 'error':
      return (
        <TransferError
          transferItem={transferItem}
          onRemove={() => onCancelTransfer(transferItem.fileId)}
          disabled={disabled}
        />
      )
    case 'idle':
      return (
        <IdleStateContent
          {...props}
          onPreviewClick={isPreviewable ? () => onOpenPreview(transferItem.fileId) : undefined}
        />
      )
  }
}

