import { DriveFile } from 'src/app/components/resource-page/drive-window/drive-layout/drive-file';
import { ID } from '../server-services/query-records/common-records';
import { NanoThumbnailResponse } from './nano-requests';
import { AppStorage } from 'src/app/shared/app-storage';
import { AdvancedSettingsEnum } from 'src/app/components/advanced-settings/advanced-settings.component';

export class ThumbnailCache {
  /**
   * {room+path:
   *    {name+size+mtime+imgb: data}
   * }
   */
  private cachedThumbnails: {
    [key: string]: { [key: string]: NanoThumbnailResponse };
  } = {};

  /**
   * Store the keys inorder so you can clear the cache after a while
   */
  private cacheTopLevelKeys: string[] = [];
  public static MAX_CACHED_ELEMENTS: number =
    parseInt(AppStorage.getItem(AdvancedSettingsEnum.MAX_THUMBNAIL_CACHE)) || 10000;

  private makeThumbnailTopLevelCacheKey(roomId: ID, path: string) {
    return '' + roomId + path;
  }

  private makeThumbnailBottomLevelCacheKey(
    name: string,
    size: number,
    mtime: number,
    imgb: number
  ) {
    return '' + name + size + mtime + imgb;
  }

  private getCurrentlyCachedElementsSize(): number {
    let elements = 0;
    this.cacheTopLevelKeys.forEach((key) => {
      if (this.cachedThumbnails[key]) {
        elements += Object.keys(this.cachedThumbnails[key]).length;
      }
    });
    return elements;
  }

  public getCachedThumbnails(
    roomId: ID,
    path: string,
    files: DriveFile[]
  ): NanoThumbnailResponse[] | null {
    let topLevelKey = this.makeThumbnailTopLevelCacheKey(roomId, path);
    let result: NanoThumbnailResponse[] = [];

    if (this.cachedThumbnails[topLevelKey]) {
      let thumbnails = this.cachedThumbnails[topLevelKey];
      for (let i = 0; i < files.length; i++) {
        if (files[i].imgb) {
          let bottomLevelKey = this.makeThumbnailBottomLevelCacheKey(
            files[i].fullName,
            files[i].size,
            files[i].mtime,
            files[i].imgb
          );

          if (!thumbnails[bottomLevelKey]) {
            return null;
          } else {
            result.push(thumbnails[bottomLevelKey]);
          }
        }
      }
    } else {
      return null;
    }

    return result;
  }

  public setCachedThumbnails(
    roomId: ID,
    path: string,
    files: DriveFile[],
    thumbnails: NanoThumbnailResponse[]
  ) {
    let topLevelKey = this.makeThumbnailTopLevelCacheKey(roomId, path);

    this.cachedThumbnails[topLevelKey] = {};

    thumbnails.forEach((thmb) => {
      let file = files.find((f) => f.fullName === thmb.name);
      if (file) {
        let bottomLevelKey = this.makeThumbnailBottomLevelCacheKey(
          file.fullName,
          file.size,
          file.mtime,
          file.imgb
        );

        this.cachedThumbnails[topLevelKey][bottomLevelKey] = thmb;
      }
    });
    this.cacheTopLevelKeys.push(topLevelKey);

    let size = this.getCurrentlyCachedElementsSize();

    // check the cache limit
    while (size > ThumbnailCache.MAX_CACHED_ELEMENTS && this.cacheTopLevelKeys.length > 1) {
      let topLevelKey = this.cacheTopLevelKeys.shift();
      if (this.cachedThumbnails[topLevelKey]) {
        delete this.cachedThumbnails[topLevelKey];
      }
    }
  }
}
