export type ScanSource = "flatbed" | "adf";
export type ColorMode = "RGB" | "BW" | "GRAY";
export type TransferMode = "memory" | "file" | "native";

export interface ScanConfig {
  showUI: boolean;
  dpi_x: number;
  dpi_y: number;
  deviceIndex: number;
  showDialog: boolean;
  scanSource: ScanSource;
  autoFeed: boolean;
  dupxMode: boolean;
  autoDeskew: boolean;
  autoBorderDetection: boolean;
  colorMode: ColorMode;
  transMode: TransferMode;
  /** Legacy compatibility only. Prefer `scanSource`. */
  autoFeedEnable?: boolean;
}

export interface ImageInfo {
  index: number;
  imageId?: string;
  width?: number;
  height?: number;
  imageBase64?: string;
  [key: string]: any;
}

export interface UploadResult {
  success?: boolean;
  message?: string;
  error?: string;
  raw?: string | null;
  [key: string]: any;
}

export interface UploadRequestHeaderInput {
  name: string;
  value: string | number | boolean;
}

export type UploadRequestHeadersInput =
  | Record<string, string | number | boolean>
  | Array<UploadRequestHeaderInput>
  | null
  | undefined;

export interface WebSocketMessage {
  cmd_type: string;
  protocolVersion?: number;
  ok?: boolean;
  success?: boolean;
  msg?: string;
  message?: string;
  error?: string;
  imageCount?: number;
  currentIndex?: number;
  currentSelected?: number;
  selectedImageId?: string | null;
  imageId?: string;
  imageIndex?: number;
  index?: number;
  oldIndex?: number;
  newIndex?: number;
  beforeIndex?: number;
  afterIndex?: number;
  beforeImageCount?: number;
  afterImageCount?: number;
  scanSource?: ScanSource;
  autoFeedEnable?: boolean;
  autoFeed?: boolean;
  dupxMode?: boolean;
  autoDeskew?: boolean;
  autoBorderDetection?: boolean;
  colorMode?: ColorMode | string;
  transMode?: TransferMode | string;
  scanJobId?: string;
  source?: string;
  loadedCount?: number;
  imageAfterCount?: number;
  images?: string[];
  imageInfos?: ImageInfo[];
  imageBase64?: string;
  response?: string | null;
  uploadResult?: string | UploadResult;
  uploadResultJson?: UploadResult;
  uploadSucceeded?: boolean;
  uploadMessage?: string;
  uploadHeaderCount?: number;
  uploadHeaderNames?: string[];
  headersCleared?: boolean;
  devices?: any[];
  [key: string]: any;
}

export interface Base64ImagePayload {
  data: string;
  format?: string;
}

export default class ScanOnWeb {
  protocolVersion: number;
  serverProtocolVersion: number | null;
  scaner_work_config: ScanConfig & {
    /** Legacy compatibility only. Prefer `scanSource`. */
    autoFeedEnable?: boolean;
  };
  h5socket: WebSocket | null;
  imageCount: number;

  onGetDevicesListEvent?: (msg: WebSocketMessage) => void;
  onScanFinishedEvent?: (msg: WebSocketMessage) => void;
  onSelectScanDeviceEvent?: (msg: WebSocketMessage) => void;
  onGetImageCountEvent?: (msg: WebSocketMessage) => void;
  onImageListSnapshotEvent?: (msg: WebSocketMessage) => void;
  onImageSnapshotEvent?: (msg: WebSocketMessage) => void;
  onScanPageAddedEvent?: (msg: WebSocketMessage) => void;
  onGetAllImageEvent?: (msg: WebSocketMessage) => void;
  onGetImageByIdEvent?: (msg: WebSocketMessage) => void;
  onLoadImageFromUrlEvent?: (msg: WebSocketMessage) => void;
  onLoadImageFromBase64Event?: (msg: WebSocketMessage) => void;
  onRotateImageEvent?: (msg: WebSocketMessage) => void;
  onGetImageSizeEvent?: (msg: WebSocketMessage) => void;
  onUploadAllImageAsPdfToUrlEvent?: (msg: WebSocketMessage) => void;
  onUploadAllImageAsTiffToUrlEvent?: (msg: WebSocketMessage) => void;
  onUploadJpgImageByIndexEvent?: (msg: WebSocketMessage) => void;
  onSetUploadRequestHeadersEvent?: (msg: WebSocketMessage) => void;
  onUploadEvent?: (msg: WebSocketMessage) => void;
  onOpenClientLocalMultipageFileEvent?: (msg: WebSocketMessage) => void;
  onImageEditedEvent?: (msg: WebSocketMessage) => void;
  onImageMovedEvent?: (msg: WebSocketMessage) => void;
  onImageDrapEvent?: (msg: WebSocketMessage) => void;
  onImageDeletedEvent?: (msg: WebSocketMessage) => void;
  onImagesClearedEvent?: (msg: WebSocketMessage) => void;

  constructor();

  getConnectedServer(wssUrls: string[]): Promise<WebSocket>;
  tryConnect(): void;
  initWebsocketCallback(server: WebSocket): void;
  onSocketError(event: Event): void;
  isCallbackExist(f: any): f is Function;
  dispatchCallback(name: string, msg: WebSocketMessage): void;
  isUploadCommandType(cmdType: string): boolean;
  extractUploadResult(msg: WebSocketMessage): UploadResult | null;
  resolveUploadMessage(msg: WebSocketMessage, fallback?: string): string;
  normalizeUploadMessage(msg: WebSocketMessage): WebSocketMessage;
  toBoolCompat(value: any): boolean;
  toIntCompat(value: any, fallback: number): number;
  normalizeScanSource(
    scanSource?: string | null,
    legacyAutoFeedEnable?: any
  ): ScanSource;
  getLegacyAutoFeedEnable(scanSource?: string | null): boolean;
  shouldIncludeLegacyAutoFeedEnable(): boolean;
  normalizeScanConfig(
    config?: Partial<ScanConfig> & { autoFeedEnable?: boolean },
    options?: { includeLegacyAutoFeedEnable?: boolean }
  ): ScanConfig & { autoFeedEnable?: boolean };
  recordServerProtocolVersion(msg: WebSocketMessage): number;
  applyIncomingScanConfig(msg: WebSocketMessage): void;
  normalizeIncomingMessage(rawMsg: WebSocketMessage): WebSocketMessage;
  onSocketMessage(event: MessageEvent): void;
  normalizeOutgoingCommand(commandData: Record<string, any>): Record<string, any>;
  sendWebSocketCommand(commandData: object): void;
  setLicenseKey(
    licenseMode: string,
    key1: string,
    key2: string,
    licenseServerUrl: string
  ): void;
  loadDevices(): void;
  selectScanDevice(deviceIndex: number): void;
  startScan(): void;
  clearAll(): void;
  getImageCount(): void;
  getAllImage(): void;
  getImageById(indexOrImageId: number | string): void;
  loadImageFromUrl(url: string, type?: string): void;
  loadImageFromBase64(base64Data: string, format?: string): void;
  rotateImage(index: number, angle: number): void;
  getImageSize(index: number): void;
  deleteImageByIndex(index: number, imageId?: string): void;
  moveImage(oldIndex: number, newIndex: number): void;
  setUploadRequestHeaders(headers?: UploadRequestHeadersInput): void;
  uploadAllImageAsPdfToUrl(url: string, id: string, desc: string): void;
  uploadAllImageAsTiffToUrl(url: string, id: string, desc: string): void;
  uploadJpgImageByIndex(
    url: string,
    id: string,
    desc: string,
    index: number
  ): void;
  saveAllImageToLocal(filename: string): void;
  openClientLocalfile(): void;
  openClientLocalMultipageFile(): void;
  ftpUploadAllImage(
    serverIp: string,
    port: number,
    username: string,
    password: string,
    serverPath: string,
    filename: string
  ): void;
  setUploadButtonVisible(visible: boolean): void;
  setFocus(): void;
  hidden(): void;
  closeWebSocket(): void;
  loadMultipleImagesFromBase64(base64Images: Base64ImagePayload[]): void;
  loadImageFromCanvas(
    canvas: HTMLCanvasElement,
    format?: string,
    quality?: number
  ): void;
  loadImageFromFileInput(fileInput: HTMLInputElement): void;
}
