import {service} from '@loopback/core';
import {CurrentContext, EntityActionType, ObjectNode} from '../..';
import {NodeInterceptService} from '../../services/entity-intercept/node-intercept.service';
import {CONTENT_IMAGE_PROVIDER, IMAGE_TYPE} from './content-image.const';
import {Image} from './content-image.interface';
import {TransientImageService} from './transient-image.service';

export class InterceptImageService {
  constructor(
    @service(TransientImageService)
    private transientImageService: TransientImageService,
    @service(NodeInterceptService)
    private nodeInterceptService: NodeInterceptService,
  ) {
    this.nodeInterceptService.registerEntityInterceptorService(
      CONTENT_IMAGE_PROVIDER,
      InterceptImageService.name,
      'Set position and date from Exif image data and Reduce big image size',
      IMAGE_TYPE.name,
      EntityActionType.create,
      this.interceptImageCreate.bind(this),
    );
    this.nodeInterceptService.registerEntityInterceptorService(
      CONTENT_IMAGE_PROVIDER,
      InterceptImageService.name,
      'Reduce big image size',
      IMAGE_TYPE.name,
      EntityActionType.update,
      this.interceptImageUpdate.bind(this),
    );
  }

  public async interceptImageCreate(
    entityId: string | undefined,
    image: ObjectNode,
    requestEntity: Partial<ObjectNode>,
    ctx: CurrentContext,
  ): Promise<boolean> {
    try {
      if (!requestEntity.imagePosition || !requestEntity.imageDate) {
        const exif: {
          latitude?: number;
          longitude?: number;
          CreateDate?: Date;
          DateTimeOriginal?: Date;
          ModifyDate?: Date;
        } = (await this.transientImageService.getImageExif(
          requestEntity as Image,
        )) as {
          latitude?: number;
          longitude?: number;
          CreateDate?: Date;
          DateTimeOriginal?: Date;
          ModifyDate?: Date;
        };
        if (!requestEntity.imagePosition) {
          const position = this.transientImageService.getPositionFromExif(exif);
          if (position) {
            requestEntity.imagePosition = position;
          }
        }
        if (!requestEntity.imageDate) {
          const date = this.transientImageService.getImageDateFromExif(exif);
          if (date) {
            requestEntity.imageDate = date;
          }
        }
      }
    } catch (error) {}

    return this.checkAndreduceImageEntitySize(requestEntity);
  }

  public async interceptImageUpdate(
    entityId: string | undefined,
    entity: ObjectNode,
    requestEntity: Partial<ObjectNode>,
    ctx: CurrentContext,
  ): Promise<boolean> {
    return this.checkAndreduceImageEntitySize(requestEntity);
  }

  public async checkAndreduceImageEntitySize(
    image: Partial<Image>,
  ): Promise<boolean> {
    if (image && image.contentImage) {
      return await this.checkAndReduceImageSize(image.contentImage);
    }
    return true;
  }

  public async checkAndReduceImageSize(image: {
    base64: string;
    size: string;
  }): Promise<boolean> {
    try {
      if (image && image.base64) {
        const imageSizeCheck: {
          base64: string;
          size: string;
        } = await this.transientImageService.changeImgSize(image, 4000);
        if (imageSizeCheck.size !== image.size) {
          image.base64 = imageSizeCheck.base64;
          image.size = imageSizeCheck.size;
        }
      }
    } catch (error) {}
    return true;
  }
}
