import type { Workbook, Worksheet } from '@univerjs/core';
import type { Observable } from 'rxjs';

import {
  generateRandomId,
  IImageIoService,
  IImageIoServiceParam,
  ImageSourceType,
  ImageUploadStatusType,
  Inject,
  Injector,
  IUniverInstanceService,
  Nullable,
  UniverInstanceType,
} from '@univerjs/core';
import { IRenderManagerService } from '@univerjs/engine-render';
import { SheetSkeletonManagerService } from '@univerjs/sheets-ui';
import { Subject } from 'rxjs';

export const DRAWING_IMAGE_ALLOW_SIZE = 5 * 1024 * 1024;

export const DRAWING_IMAGE_ALLOW_IMAGE_LIST = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/bmp'];

export class JnpfSheetImageIoImplService implements IImageIoService {
  private _change$ = new Subject<number>();

  change$ = this._change$ as Observable<number>;
  private _imageSourceCache: Map<string, HTMLImageElement> = new Map();

  private _waitCount = 0;

  constructor(
    @Inject(Injector) private readonly _accessor: Injector,
    @IUniverInstanceService protected readonly _univerInstanceService: IUniverInstanceService,
  ) {}

  addImageSourceCache(source: string, imageSourceType: ImageSourceType, imageSource: Nullable<HTMLImageElement>) {
    if (imageSourceType === ImageSourceType.BASE64 || imageSource == null) {
      return;
    }
    this._imageSourceCache.set(source, imageSource);
  }

  cacheImages() {
    const { sheet, unitId, subUnitId } = this._sheet();
    const skeleton = this._getSkeleton(unitId, subUnitId);
    if (!skeleton) {
      return;
    }
    skeleton.resetCache();
    sheet.getCellMatrix().forValue((_row, _col, value) => {
      if (value && value.p && value.p.drawings) {
        Object.keys(value.p.drawings).forEach(drawing => {
          const drawingItem: any = value.p?.drawings?.[drawing];
          if (value.p && value.p.drawings && drawingItem && drawingItem.imageSourceType === 'BASE64' && drawingItem.source) {
            this._imageSourceCache.set(drawingItem.imageSourceType, drawingItem.source);
            // 强制缓存
            skeleton.imageCacheMap.getImage(drawingItem.imageSourceType, drawingItem.source);
          }
        });
      }
    });
  }

  clearMemory() {}

  async getImage(imageId: string): Promise<string> {
    return imageId;
  }

  getImageSourceCache(source: string, imageSourceType: ImageSourceType) {
    if (imageSourceType === ImageSourceType.BASE64) {
      const image = new Image();
      image.src = source;
      return image;
    }
    return this._imageSourceCache.get(source);
  }

  async saveImage(imageFile: File): Promise<Nullable<IImageIoServiceParam>> {
    return new Promise((resolve, reject) => {
      if (!DRAWING_IMAGE_ALLOW_IMAGE_LIST.includes(imageFile.type)) {
        reject(new Error(ImageUploadStatusType.ERROR_IMAGE_TYPE));
        this._decreaseWaiting();
        return;
      }
      if (imageFile.size > DRAWING_IMAGE_ALLOW_SIZE) {
        reject(new Error(ImageUploadStatusType.ERROR_EXCEED_SIZE));
        this._decreaseWaiting();
        return;
      }
      // 获取上传的图片的宽高
      const reader = new FileReader();
      reader.readAsDataURL(imageFile);
      reader.addEventListener('load', evt => {
        const replaceSrc = evt.target?.result as string;
        if (replaceSrc == null) {
          reject(new Error(ImageUploadStatusType.ERROR_IMAGE));
          this._decreaseWaiting();
          return;
        }

        const imageId = generateRandomId(6);
        resolve({
          imageId,
          imageSourceType: ImageSourceType.BASE64,
          source: replaceSrc,
          base64Cache: replaceSrc,
          status: ImageUploadStatusType.SUCCUSS,
        });

        this._decreaseWaiting();
      });
    });
  }

  setWaitCount(count: number) {
    this._waitCount = count;
    this._change$.next(count);
  }

  private _decreaseWaiting() {
    this._waitCount -= 1;
    this._change$.next(this._waitCount);
  }

  private _getSkeleton(unitId: string, subUnitId: string) {
    return this._accessor.get(IRenderManagerService)?.getRenderById(unitId)?.with(SheetSkeletonManagerService)?.getOrCreateSkeleton({ sheetId: subUnitId });
  }

  private _sheet() {
    // 使用 `UniverInstanceService` 获取当前类型为 `UNIVER_SHEET` 的活动单元实例
    const unit: Nullable<Workbook> = this._univerInstanceService.getCurrentUnitForType<Workbook>(UniverInstanceType.UNIVER_SHEET);
    const unitId = unit!.getUnitId();
    const sheet: Worksheet = unit!.getActiveSheet();
    const subUnitId = sheet?.getSheetId();
    return {
      unit,
      sheet,
      unitId,
      subUnitId,
    };
  }
}
