import type { CloudlyApiClient } from './classes.cloudlyapiclient.js';
import * as plugins from './plugins.js';

export class Image implements plugins.servezoneInterfaces.data.IImage {
  public static async getImages(cloudlyClientRef: CloudlyApiClient) {
    const getAllImagesTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.image.IRequest_GetAllImages>(
      'getAllImages'
    );
    const response = await getAllImagesTR.fire({
      identity: cloudlyClientRef.identity,
    });
    const resultImages: Image[] = [];
    for (const image of response.images) {
      const newImage = new Image(cloudlyClientRef);
      Object.assign(newImage, image);
      resultImages.push(newImage);
    }
    return resultImages;
  }

  public static async getImageById(cloudlyClientRef: CloudlyApiClient, imageIdArg: string) {
    const getImageByIdTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.image.IRequest_GetImage>(
      'getImage'
    );
    const response = await getImageByIdTR.fire({
      identity: cloudlyClientRef.identity,
      imageId: imageIdArg,
    });
    const newImage = new Image(cloudlyClientRef);
    Object.assign(newImage, response.image);
    return newImage;
  }

  /**
   * creates a new image 
   */
  public static async createImage(cloudlyClientRef: CloudlyApiClient, imageDataArg: Partial<plugins.servezoneInterfaces.data.IImage['data']>) {
    const createImageTR = cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.image.IRequest_CreateImage>(
      'createImage'
    );
    const response = await createImageTR.fire({
      identity: cloudlyClientRef.identity,
      name: imageDataArg.name,
      description: imageDataArg.description,
    });
    const newImage = new Image(cloudlyClientRef);
    Object.assign(newImage, response.image);
    return newImage;
  }

  // INSTANCE
  cloudlyClientRef: CloudlyApiClient;

  id: plugins.servezoneInterfaces.data.IImage['id'];
  data: plugins.servezoneInterfaces.data.IImage['data'];

  constructor(cloudlyClientRef: CloudlyApiClient) {
    this.cloudlyClientRef = cloudlyClientRef;
  }

  /**
   * updates the image data
   */
  public async update() {
    const getVersionsTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.image.IRequest_GetImage>(
      'getImage'
    );
    const response = await getVersionsTR.fire({
      identity: this.cloudlyClientRef.identity,
      imageId: this.id,
    });
    Object.assign(this, response.image);
  }

  /**
   * pushes a new version of the image
   * @param imageVersion 
   * @param imageReadableArg 
   */
  public async pushImageVersion(imageVersion: string, imageReadableArg: ReadableStream<Uint8Array>): Promise<void> {
    const done = plugins.smartpromise.defer();
    const pushImageTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.image.IRequest_PushImageVersion>(
      'pushImageVersion'
    );
    const virtualStream = new plugins.typedrequest.VirtualStream();
    const response = await pushImageTR.fire({
      identity: this.cloudlyClientRef.identity,
      imageId: this.id,
      versionString: '',
      imageStream: virtualStream,
    });
    await virtualStream.readFromWebstream(imageReadableArg);
    await this.update();
  };

  /**
   * pulls a version of the image
   */
  public async pullImageVersion(versionStringArg: string): Promise<ReadableStream<Uint8Array>> {
    const pullImageTR = this.cloudlyClientRef.typedsocketClient.createTypedRequest<plugins.servezoneInterfaces.requests.image.IRequest_PullImageVersion>(
      'pullImageVersion'
    );
    const response = await pullImageTR.fire({
      identity: this.cloudlyClientRef.identity,
      imageId: this.id,
      versionString: versionStringArg,
    });
    const imageStream = response.imageStream;
    const webduplexStream = new plugins.webstream.WebDuplexStream({});
    imageStream.writeToWebstream(webduplexStream.writable);
    return webduplexStream.readable;
  };
}
