import { createContext, ReactElement, ReactNode } from 'react'

import type {
  IFileItem,
  IFileTransfer,
  IFileValidateDetail,
  TFileUploadStrategy,
  TTransferProgress,
} from 'shared-types'

import { uuidish } from '../../utils/stringutils'

/** Unique identifier assigned to each selected file. */
export type TFileId = string

/**
 * A selected file plus metadata used by the FileUpload UI.
 *
 * Notes:
 * - A `fileId` is generated automatically if omitted.
 * - `attributes.targetFilename` is the filename shown in the queue and may be updated by extensions (e.g. rename).
 *
 * Implements the shared `IFileItem` type from `shared-types`.
 */
export class FileItem implements IFileItem {
  fileId: TFileId
  file: File
  attributes: { targetFilename: string } & Record<string, unknown>

  constructor(file: File, fileId?: TFileId) {
    this.fileId = fileId || uuidish()
    this.file = file
    this.attributes = {
      targetFilename: file.name,
    }
  }
}

/** Internal context used by queue item operations and hidden inputs. */
export type TPktFileUploadContext = { name?: string; multiple: boolean; id?: string }
export const PktFileUploadContext = createContext<TPktFileUploadContext>({} as TPktFileUploadContext)

/** The value type for `PktFileUpload` (`value` / `defaultValue`). */
export type TFileItemList = Array<FileItem>

/** Transfer status for a file when using `uploadStrategy="custom"` — aliased from `shared-types`. */
export type TFileTransfer = IFileTransfer

/** Upload mode: `form` posts the files on submit, `custom` posts file IDs and uploads separately. */
export type TUploadStrategy = TFileUploadStrategy

/** Detail payload passed to the React `onFileValidate` escape hatch. */
export type TFileValidateDetail = IFileValidateDetail

/** Re-export for parity with Lit types. */
export type { TTransferProgress }

export type TFileAttribute<T> = {
  get: (fileId: TFileId) => T | undefined
  set: (fileId: TFileId, attributeValue: T | undefined) => void
}
export type TFileAttributes = <T>(attributeName: string) => TFileAttribute<T>

/**
 * Context passed to queue-item operations. Mirrors the Lit
 * `TQueueOperationContext` so operations authored for one runtime are
 * trivial to port to the other.
 */
export type TQueueOperationContext = {
  file: FileItem
  inputName: string
  disabled: boolean
  isActive: boolean
  activate: () => void
  close: () => void
  getAttribute: <T>(name: string) => T | undefined
  setAttribute: (name: string, value: unknown) => void
}

export type TQueueOperationLabel = string | ((fileItem: FileItem) => string)

/**
 * An operation that can be attached to a queue item (rename, comment, remove, etc).
 *
 * Must carry a stable `id: string` — symbols are no longer supported.
 */
export type TQueueItemOperation = {
  id: string
  title: TQueueOperationLabel
  ariaLabel?: TQueueOperationLabel
  onClick?: (context: TQueueOperationContext) => void
  renderInlineUI?: (context: TQueueOperationContext) => ReactNode
  renderExtendedUI?: (context: TQueueOperationContext) => ReactNode
  renderContent?: (context: TQueueOperationContext) => ReactNode
  renderHidden?: (context: TQueueOperationContext) => ReactNode
}

export type TFileAndTransfer = FileItem &
  Pick<TFileTransfer, 'progress' | 'errorMessage' | 'showProgress' | 'lastProgress'>
export type TTransferItemInProgress = TFileAndTransfer & { progress: number }

/**
 * Custom renderer for how a queue item is displayed (e.g. filename vs thumbnail grid).
 *
 * Must return a renderable React element (or `null`).
 */
export type TItemRenderer = (props: {
  transferItem: TFileAndTransfer
  queueItemOperations: Array<TQueueItemOperation>
  onPreviewClick?: () => void
}) => ReactElement | null
