import type {ImageData} from "./ImageData";
import {NativeModules} from "react-native";
import type {EnumColourChannelUsageType} from "./EnumColourChannelUsageType";
import {CameraEnhancer} from "../dce";
import {CaptureVisionRouter} from "../cvr";

// @ts-ignore Check whether __turboModuleProxy exists, it may not
const isTurboModuleEnabled = global.__turboModuleProxy != null;

const ISAModule = isTurboModuleEnabled ?
  require("./NativeDynamsoftImageSourceAdapterModule").default :
  NativeModules.DynamsoftImageSourceAdapterModule

let isInstalled = false
const installMethods = () => {
  if (!isInstalled) {
    ISAModule.install()
    isInstalled = true
  }
}

declare global {
  function isaAddImageToBuffer(nativeIsaId: string, imageData: ImageData): void;

  function isaGetImageData(nativeIsaId: string): ImageData | null | undefined;
}


/**
 * The ImageSourceAdapter class provides an interface for fetching and buffering images.
 * It is an abstract class that needs to be implemented by a concrete class to provide actual functionality.
 * `Each ImageSourceAdapter instance object will correspond to a native instance object.`
 *
 * @see {@link CameraEnhancer}
 * @see {@link CaptureVisionRouter.setInput}
 * @hideconstructor
 * */
export abstract class ImageSourceAdapter {
  protected isaId: string = "";

  protected constructor() {
    this.init();
  }

  protected init() {
    this.isaId = ISAModule.createDefaultNativeISA();
  }

  /**@internal*/
  public _getIsaId(): string {
    return this.isaId;
  }

  /**
   * Destroy native instance. This object is no longer available after destroy().
   * */
  public destroy(): void {
    ISAModule.destroy(this.isaId);
  }

  /**
   * Adds an image to the buffer of the adapter.
   *
   * @param imageData The {@link ImageData} object to be added to the buffer.
   * */
  public addImageToBuffer(imageData: ImageData): void {
    installMethods()
    if (typeof global.isaAddImageToBuffer !== 'function') {
      return;
    }
    global.isaAddImageToBuffer(this.isaId, imageData)
  }

  /**
   * Get a buffered image.
   *
   * @returns {ImageData|null|undefined} - The {@link ImageData} object if available, otherwise`null` or `undefined` if no image is found in the buffer.
   * */
  public getImageData(): ImageData | null | undefined {
    installMethods()
    if (typeof global.isaGetImageData !== 'function') {
      return null;
    }
    return global.isaGetImageData(this.isaId)
  }

  /**
  * Get the current number of images in the buffer.
  *
  * @returns {Promise<number>} - A promise that resolves to the number of images in the buffer.
  * */
  public getImageCount(): Promise<number> {
    return ISAModule.getImageCount(this.isaId);
  }

  /**
   * Determines whether the buffer is empty.
   * */
  public isBufferEmpty(): Promise<boolean> {
    return ISAModule.isBufferEmpty(this.isaId);
  }

  /**
   * Clear the image buffer.
   * */
  public clearBuffer(): Promise<void> {
    return ISAModule.clearBuffer(this.isaId);
  }


  /**
   *  Get the current usage type for color channels in images.
   *
   * @returns {Promise<EnumColourChannelUsageType>} - A promise that resolves to an enum representing the color channel usage type.
   * */
  public getColourChannelUsageType(): Promise<EnumColourChannelUsageType> {
    return ISAModule.getColourChannelUsageType(this.isaId);
  }

  /**
   * Set the usage type of a color channel in images.
   *
   * @param type The usage type({@link EnumColourChannelUsageType}) to be set for the color channel.
   * */
  public setColourChannelUsageType(type: EnumColourChannelUsageType): Promise<void> {
    return ISAModule.setColourChannelUsageType(this.isaId, type);
  }

  /**
   * Get the maximum number of images that can be buffered.
   *
   * @return {Promise<number>} - A promise that resolves to the maximum capability of the Buffer.
   * */
  public getMaximumImageCount(): Promise<number> {
    return ISAModule.getMaximumImageCount(this.isaId);
  }

  /**
   * Set the maximum number of images that can be buffered at any time.
   *
   * @param count - The maximum capability of the Buffer.
   * */
  public setMaximumImageCount(count: number): Promise<void> {
    return ISAModule.setMaximumImageCount(this.isaId, count);
  }

  /**
   * Start fetching images from the source to the Buffer of ImageSourceAdapter.
   * */
  public startFetching(): void {
    ISAModule.startFetching(this.isaId);
  }

  /**
   * Stop fetching images from the source to the Buffer of ImageSourceAdapter.
   * */
  public stopFetching(): void {
    ISAModule.stopFetching(this.isaId);
  }
}
