import * as plugins from './levelcache.plugins.js';
import { AbstractCache } from './levelcache.abstract.classes.cache.js';
import { LevelCache } from './levelcache.classes.levelcache.js';
import { CacheEntry } from './levelcache.classes.cacheentry.js';

/**
 *
 */
export class CacheS3Manager extends AbstractCache {
  private levelCacheRef: LevelCache;
  private smartbucket: plugins.smartbucket.SmartBucket;
  private s3CacheBucket: plugins.smartbucket.Bucket;
  private s3CacheDir: plugins.smartbucket.Directory;
  private readyDeferred = plugins.smartpromise.defer<void>();

  public ready = this.readyDeferred.promise;
  public status: 'active' | 'inactive';

  constructor(levelCacheRefArg: LevelCache) {
    super();
    this.levelCacheRef = levelCacheRefArg;
    this.init();
  }

  public async init() {
    if (this.levelCacheRef.options.s3Config) {
      this.smartbucket = new plugins.smartbucket.SmartBucket(this.levelCacheRef.options.s3Config);
      this.s3CacheBucket = await this.smartbucket.getBucketByName('');
      this.s3CacheDir = await (
        await this.s3CacheBucket.getBaseDirectory()
      ).getSubDirectoryByName(this.levelCacheRef.options.cacheId);
      if (this.levelCacheRef.options.maxS3StorageInMB) {
        console.log(`cache level S3 activated with ${this.levelCacheRef.options.maxS3StorageInMB}`);
      } else {
        console.log(`s3 cache started without limit. Automatically applying timebox of 1 month`);
      }
      this.status = 'active';
    } else {
      this.status = 'inactive';
    }
    this.readyDeferred.resolve();
  }

  public async retrieveCacheEntryByKey(keyArg: string): Promise<CacheEntry> {
    const jsonFileString = (await this.s3CacheDir.fastGet({
      path: encodeURIComponent(keyArg),
    })).toString();
    const cacheEntry = CacheEntry.fromStorageJsonString(jsonFileString);
    return cacheEntry;
  }

  public async storeCacheEntryByKey(keyArg: string, cacheEntryArg: CacheEntry) {
    await this.s3CacheDir.fastPut({
      path: encodeURIComponent(keyArg),
      contents: cacheEntryArg.toStorageJsonString()
    });
  }

  public async checkKeyPresence(keyArg: string): Promise<boolean> {
    const files = await this.s3CacheDir.listFiles();
    for (const file of files) {
      if (file.name === keyArg) {
        return true;
      }
    }
    return false;
  }

  public async deleteCacheEntryByKey(keyArg: string) {
    if (this.status === 'active') {
      await this.s3CacheDir.fastRemove({
        path: encodeURIComponent(keyArg),
      });
    }
  }

  /**
   * clean outdated
   */
  public async cleanOutdated() {}

  public async cleanAll() {
    await this.s3CacheDir.delete({
      mode: 'permanent',
    });
  }
}
