import { RefObject, useEffect, useState } from 'react'

import { getDisplayFilename, trapTabInside } from 'shared-utils/fileupload'

import { PktButton } from '../button/Button'
import { PktIcon } from '../icon/Icon'
import { PktProgressbar } from '../progressbar/Progressbar'
import { PktModal } from '../modal/Modal'
import { Truncate } from './Truncate'
import { TFileAndTransfer, TQueueItemOperation, TQueueOperationContext, TTransferItemInProgress } from './types'
import { formatFileSize } from './utils'

const CancelTransferButton = (props: {
  onClick: () => void
  label?: string
  ariaLabel?: string
  disabled?: boolean
}) => (
  <button
    type="button"
    onClick={props.onClick}
    disabled={props.disabled}
    className="pkt-fileupload__queue-display__item__cancel-button"
    aria-label={props.ariaLabel || 'Avbryt opplasting'}
  >
    {props.label || 'Avbryt'}
  </button>
)

const LoadingText = () => (
  <span className="pkt-fileupload__queue-display__item__loading-text" aria-label="Laster opp fil">
    Laster opp
  </span>
)

export const TransferInProgress = ({
  cancelTransfer,
  transferItem,
  disabled = false,
}: {
  transferItem: TTransferItemInProgress
  cancelTransfer: () => void
  disabled?: boolean
}) => {
  const showProgressBar = transferItem.showProgress ?? transferItem.progress !== 0

  return (
    <>
      <PktIcon
        name="document-text"
        className="pkt-fileupload__queue-display__item__icon pkt-icon--medium"
        aria-hidden="true"
      />
      <p className="pkt-fileupload__queue-display__item__title" aria-label="Filnavn">
        <Truncate>{getDisplayFilename(transferItem)}</Truncate>
        <span className="pkt-fileupload__queue-display__item__filesize">
          {' '}
          ({formatFileSize(transferItem.file.size)})
        </span>
      </p>
      <CancelTransferButton onClick={cancelTransfer} disabled={disabled} />
      {showProgressBar ? (
        <>
          <PktProgressbar
            valueCurrent={transferItem.progress * 100}
            statusType={'none'}
            valueMax={100}
            statusPlacement={'following'}
            className="pkt-fileupload__queue-display__item__progress"
          />
          <span className="pkt-fileupload__queue-display__item__percentage" aria-hidden="true">
            {`${Math.round(transferItem.progress * 100)}%`}
          </span>
        </>
      ) : (
        <LoadingText />
      )}
    </>
  )
}

const TitleWithSize = ({ transferItem }: { transferItem: TFileAndTransfer }) => (
  <p className="pkt-fileupload__queue-display__item__title">
    <Truncate>{getDisplayFilename(transferItem)}</Truncate>
    {transferItem.file && (
      <span className="pkt-fileupload__queue-display__item__filesize">
        {' '}
        ({formatFileSize(transferItem.file.size)})
      </span>
    )}
  </p>
)

// Error state with progress bar (when showProgress was true during upload)
const TransferErrorWithProgress = ({
  transferItem,
  onRemove,
  disabled,
}: {
  transferItem: TFileAndTransfer
  onRemove: () => void
  disabled?: boolean
}) => {
  // Use lastProgress to show where the upload failed (default to 100% if not available)
  const progressValue = (transferItem.lastProgress ?? 1) * 100

  return (
    <>
      <PktIcon
        className="pkt-fileupload__queue-display__item__icon pkt-icon--medium"
        name="alert-error"
        aria-hidden="true"
      />
      <TitleWithSize transferItem={transferItem} />
      <CancelTransferButton
        onClick={onRemove}
        label="Fjern"
        ariaLabel="Fjern fil som feilet under opplasting"
        disabled={disabled}
      />
      <PktProgressbar
        valueCurrent={progressValue}
        statusType={'none'}
        valueMax={100}
        statusPlacement={'following'}
        className="pkt-fileupload__queue-display__item__progress pkt-fileupload__queue-display__item__progress--error"
      />
      {transferItem.errorMessage && (
        <span className="pkt-fileupload__queue-display__item__error-message">{transferItem.errorMessage}</span>
      )}
    </>
  )
}

// Error state without progress bar (indeterminate upload)
const TransferErrorIndeterminate = ({
  transferItem,
  onRemove,
  disabled,
}: {
  transferItem: TFileAndTransfer
  onRemove: () => void
  disabled?: boolean
}) => (
  <>
    <PktIcon
      className="pkt-fileupload__queue-display__item__icon pkt-icon--medium"
      name="alert-error"
      aria-hidden="true"
    />
    <TitleWithSize transferItem={transferItem} />
    <CancelTransferButton
      onClick={onRemove}
      label="Fjern"
      ariaLabel="Fjern fil som feilet under opplasting"
      disabled={disabled}
    />
    {transferItem.errorMessage && (
      <span className="pkt-fileupload__queue-display__item__error-message">{transferItem.errorMessage}</span>
    )}
  </>
)

// Main error component - chooses display based on showProgress
export const TransferError = ({
  transferItem,
  onRemove,
  disabled,
}: {
  transferItem: TFileAndTransfer
  onRemove: () => void
  disabled?: boolean
}) => {
  // If showProgress was true, show error with progress bar, otherwise show indeterminate error
  if (transferItem.showProgress) {
    return <TransferErrorWithProgress transferItem={transferItem} onRemove={onRemove} disabled={disabled} />
  }
  return <TransferErrorIndeterminate transferItem={transferItem} onRemove={onRemove} disabled={disabled} />
}
export const OperationButton = ({
  operation,
  context,
}: {
  operation: TQueueItemOperation
  context: TQueueOperationContext
}) => {
  const title = typeof operation.title === 'function' ? operation.title(context.file) : operation.title

  // Don't render button if title is empty (e.g., comment exists, show icons instead)
  if (!title) return null

  const onClick = () => {
    if (operation.renderInlineUI || operation.renderExtendedUI) {
      context.activate()
    }
    operation.onClick?.(context)
  }
  return (
    <button
      type="button"
      className={'pkt-fileupload__queue-display__item__operation'}
      onClick={onClick}
      disabled={context.disabled}
      aria-label={typeof operation.ariaLabel === 'function' ? operation.ariaLabel(context.file) : operation.ariaLabel}
    >
      {title}
    </button>
  )
}
export const FilenameRenderer = ({
  transferItem,
}: {
  transferItem: TFileAndTransfer
  queueItemOperations?: Array<TQueueItemOperation>
  onPreviewClick?: () => void
}) => (
  <>
    <PktIcon
      name="document-text"
      className="pkt-fileupload__queue-display__item__icon pkt-icon--medium"
      aria-hidden="true"
    />
    <TitleWithSize transferItem={transferItem} />
  </>
)

export const ThumbnailRenderer = ({
  transferItem,
  onPreviewClick,
}: {
  transferItem: TFileAndTransfer
  queueItemOperations?: Array<TQueueItemOperation>
  onPreviewClick?: () => void
}) => {
  const [thumbnailUrl, setThumbnailUrl] = useState<string | null>(null)
  const [thumbnailLoadFailed, setThumbnailLoadFailed] = useState(false)
  const file = transferItem.file

  useEffect(() => {
    setThumbnailLoadFailed(false)

    // Check if the file is an image
    if (file.type.startsWith('image/')) {
      // Create an object URL for the file
      const url = URL.createObjectURL(file)
      setThumbnailUrl(url)

      // Cleanup: revoke the object URL when component unmounts
      return () => {
        URL.revokeObjectURL(url)
      }
    }

    setThumbnailUrl(null)
  }, [file])

  const img = (thumbnailUrl && !thumbnailLoadFailed && (
    <img
      src={thumbnailUrl}
      alt={transferItem.attributes['targetFilename']}
      onError={() => setThumbnailLoadFailed(true)}
    />
  )) || <PktIcon name="document-text" className="pkt-fileupload__queue-display__item__icon pkt-icon--medium" />

  const showExpandButton = !!onPreviewClick
  const hasThumbnailPreview = !!thumbnailUrl && !thumbnailLoadFailed

  return (
    <div
      className={`pkt-fileupload__queue-display__item__thumbnail${
        hasThumbnailPreview ? '' : ' pkt-fileupload__queue-display__item__thumbnail--fallback'
      }`}
    >
      <PktButton
        className="pkt-fileupload__queue-display__item__thumbnail__image-wrapper"
        aria-label={`Forhåndsvis bilde ${transferItem.attributes['targetFilename']}`}
        type="button"
        skin="secondary"
        onClick={onPreviewClick}
      >
        {showExpandButton && (
          <PktIcon
            name="expand"
            className="pkt-fileupload__queue-display__item__thumbnail__expand-icon"
            aria-hidden="true"
          />
        )}
        {img}
      </PktButton>
      <span className="pkt-fileupload__queue-display__item__thumbnail__title">
        <Truncate>{transferItem.attributes['targetFilename']}</Truncate>
      </span>
    </div>
  )
}

// Image Preview Modal Component
// TODO: When we get an actual PktLightBox component, we can remove this component and use that instead.
interface IImagePreviewModal {
  isOpen: boolean
  images: TFileAndTransfer[]
  currentIndex: number
  onClose: () => void
  onNavigate: (direction: 'prev' | 'next') => void
  modalRef: RefObject<HTMLDialogElement | null>
}

export const ImagePreviewModal = ({
  isOpen,
  images,
  currentIndex,
  onClose,
  onNavigate,
  modalRef,
}: IImagePreviewModal) => {
  const [imageUrl, setImageUrl] = useState<string | null>(null)
  const [imageLoadFailed, setImageLoadFailed] = useState(false)
  const currentImage = images[currentIndex]
  const hasMultipleImages = images.length > 1

  useEffect(() => {
    setImageLoadFailed(false)

    if (currentImage && currentImage.file.type.startsWith('image/')) {
      const url = URL.createObjectURL(currentImage.file)
      setImageUrl(url)
      return () => URL.revokeObjectURL(url)
    }
    setImageUrl(null)
  }, [currentImage])

  useEffect(() => {
    if (!isOpen) return

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === 'Tab') {
        trapTabInside(event, modalRef.current)
        return
      }
      switch (event.key) {
        case 'ArrowLeft':
          event.preventDefault()
          onNavigate('prev')
          break
        case 'ArrowRight':
          event.preventDefault()
          onNavigate('next')
          break
        case 'Escape':
          event.preventDefault()
          onClose()
          break
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
  }, [isOpen, onNavigate, onClose, modalRef])

  if (!currentImage) return null

  return (
    <PktModal
      ref={modalRef}
      headingText={currentImage.attributes['targetFilename']}
      closeOnBackdropClick
      className="pkt-fileupload__image-preview-modal"
      onClose={onClose}
    >
      <div className="pkt-fileupload__image-preview">
        {hasMultipleImages && (
          <PktButton
            variant="icon-only"
            iconName="chevron-thin-left"
            skin="secondary"
            size="medium"
            className="pkt-fileupload__image-preview__nav pkt-fileupload__image-preview__nav--prev"
            onClick={() => onNavigate('prev')}
            aria-label={`Forrige bilde ${currentIndex} / ${images.length}`}
          />
        )}

        <div className="pkt-fileupload__image-preview__content">
          {imageUrl && !imageLoadFailed ? (
            <img
              src={imageUrl}
              alt={`${currentImage.attributes['targetFilename']} - ${currentIndex + 1} av ${images.length}`}
              className="pkt-fileupload__image-preview__image"
              onError={() => setImageLoadFailed(true)}
            />
          ) : (
            <PktIcon name="picture" className="pkt-fileupload__queue-display__item__icon pkt-icon--medium" />
          )}
        </div>

        {hasMultipleImages && (
          <span className="pkt-fileupload__image-preview__counter">
            {currentIndex + 1} / {images.length}
          </span>
        )}

        {hasMultipleImages && (
          <PktButton
            variant="icon-only"
            iconName="chevron-thin-right"
            skin="secondary"
            size="medium"
            className="pkt-fileupload__image-preview__nav pkt-fileupload__image-preview__nav--next"
            onClick={() => onNavigate('next')}
            aria-label={`Neste bilde ${currentIndex + 2} / ${images.length}`}
          />
        )}
      </div>
    </PktModal>
  )
}
