/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';

import Constants from '../../../main/ets/common/Constants';
import taskpool from '@ohos.taskpool';
import { GlobalContext } from '../../../main/ets/common/GlobalContext';
import { FileCache } from '@ohos/imageknife/src/main/ets/cache/FileCache';
import { IEngineKey, ImageKnifeOption } from '@ohos/imageknife';
import { DefaultEngineKey } from '@ohos/imageknife/src/main/ets/key/DefaultEngineKey';


export default function FileLruCacheTest() {

  describe('FileLruCacheTest', () => {
    // Defines a test suite. Two parameters are supported: test suite name and test suite function.
    beforeAll(() => {
      // Presets an action, which is performed only once before all test cases of the test suite start.
      // This API supports only one parameter: preset action function.
    });
    beforeEach(() => {
      // Presets an action, which is performed before each unit test case starts.
      // The number of execution times is the same as the number of test cases defined by **it**.
      // This API supports only one parameter: preset action function.
    });
    afterEach(() => {
      // Presets a clear action, which is performed after each unit test case ends.
      // The number of execution times is the same as the number of test cases defined by **it**.
      // This API supports only one parameter: clear action function.
    });
    afterAll(() => {
      // Presets a clear action, which is performed after all test cases of the test suite end.
      // This API supports only one parameter: clear action function.
    });

    // 测试基础put,get以及size功能
    it('assertFileSizeAllInMainThread', 0, async () => {
      const buf: ArrayBuffer = new ArrayBuffer(1024 * 1024);
      console.info(Constants.TAG + buf.byteLength)
      console.info(Constants.TAG + GlobalContext.getContext().getObject("cacheDir"))

      let fileCache: FileCache = new FileCache(GlobalContext.getContext()
        .getObject("context") as Context, 5, 3 * 1024 * 1024)
      await fileCache.initFileCache()

      fileCache.put("aaa", buf)
      await sleep(1000)
      fileCache.put("bbb", buf)
      await sleep(1000)
      fileCache.put("ccc", buf)
      expect(fileCache.size()).assertEqual(3)
      console.info(Constants.TAG + fileCache.currentMemory + "")
      fileCache.get("aaa")
      await sleep(1000)
      fileCache.put("ddd", buf)
      await sleep(1000)
      console.info(Constants.TAG + fileCache.currentMemory + "")
      expect(fileCache.size()).assertEqual(3)
      console.info(Constants.TAG + fileCache.get("aaa")?.byteLength)
      expect(fileCache.get("ddd")?.byteLength).assertEqual(buf.byteLength)
      await sleep(1000)
      expect(fileCache.get("aaa")?.byteLength).assertEqual(buf.byteLength)
      await sleep(1000)
      expect(fileCache.get("ccc")?.byteLength).assertEqual(buf.byteLength)
      await sleep(1000)
      expect(fileCache.get("bbb")).assertUndefined()


      // 模拟第二次启动后重新加载缓存
      let fileCache2: FileCache = new FileCache(GlobalContext.getContext()
        .getObject("context") as Context, 5, 3 * 1024 * 1024)
      await fileCache2.initFileCache()
      expect(fileCache2.size()).assertEqual(3)
      expect(fileCache2.get("ddd")?.byteLength).assertEqual(buf.byteLength)
      expect(fileCache2.get("aaa")?.byteLength).assertEqual(buf.byteLength)
      expect(fileCache2.get("ccc")?.byteLength).assertEqual(buf.byteLength)

    });

    it('assertFileSizeAllInSubThread', 0, async () => {
      const buf: ArrayBuffer = new ArrayBuffer(1024 * 1024);
      console.info(Constants.TAG + buf.byteLength)
      console.info(Constants.TAG + GlobalContext.getContext().getObject("cacheDir"))

      let fileCache: FileCache = new FileCache(GlobalContext.getContext()
        .getObject("context") as Context, 5, 3 * 1024 * 1024)
      await fileCache.initFileCache()

      fileCache.put("aaa", buf)

      let task: taskpool.Task = new taskpool.Task(getFile, "bbb", GlobalContext.getContext()
        .getObject("context") as Context);
      let res: ArrayBuffer | undefined = await taskpool.execute(task) as (ArrayBuffer | undefined)
      if (res !== undefined) {
        fileCache.putWithoutWriteFile("bbb", res)
      }

      task = new taskpool.Task(getFile, "aaa", GlobalContext.getContext()
        .getObject("context") as Context);
      res = await taskpool.execute(task) as (ArrayBuffer | undefined)
      if (res !== undefined) {
       fileCache.putWithoutWriteFile("aaa", res)
      }

      fileCache.put("ddd", buf)
      expect(fileCache.size()).assertEqual(3)
      expect(fileCache.currentMemory).assertEqual(3 * 1024 * 1024)
      expect(fileCache.get("bbb")?.byteLength).assertEqual(1024 * 1024)
      expect(fileCache.get("aaa")?.byteLength).assertEqual(1024 * 1024)
      expect(fileCache.get("ddd")?.byteLength).assertEqual(1024 * 1024)


      task = new taskpool.Task(getFile, "eee", GlobalContext.getContext()
        .getObject("context") as Context);

      res = await taskpool.execute(task) as (ArrayBuffer | undefined)
      if (res !== undefined) {
        fileCache.putWithoutWriteFile("eee", res)
      }
      expect(fileCache.size()).assertEqual(3)
      expect(fileCache.currentMemory).assertEqual(3 * 1024 * 1024)
      expect(fileCache.get("bbb")).assertEqual(undefined)
      expect(fileCache.get("aaa")?.byteLength).assertEqual(1024 * 1024)
      expect(fileCache.get("ddd")?.byteLength).assertEqual(1024 * 1024)

    });


    it('test', 0, async () => {
      const buf: ArrayBuffer = new ArrayBuffer(1024 * 1024);
      console.info(Constants.TAG + buf.byteLength)
      console.info(Constants.TAG + GlobalContext.getContext().getObject("cacheDir"))

      let fileCache: FileCache = new FileCache(GlobalContext.getContext()
        .getObject("context") as Context, 5, 3 * 1024 * 1024)
      await fileCache.initFileCache()

      console.info(Constants.TAG + JSON.stringify("xxxxx"))
      fileCache.put(JSON.stringify("xxxxx"),buf)
      expect(fileCache.get(JSON.stringify("xxxxx"))?.byteLength).assertEqual(1024 * 1024)
    });
    it('fileCacheEngineKey', 0, () => {
      let engineKey: IEngineKey = new DefaultEngineKey()
      let imageKnifeOption: ImageKnifeOption = {
        loadSrc:"abc"
      }
      let imageKey = engineKey.generateFileKey(imageKnifeOption.loadSrc,"")
      let imageAnimatorKey = engineKey.generateFileKey(imageKnifeOption.loadSrc,"",true)
      expect(imageKey == imageAnimatorKey).assertFalse()
    });
  });
}

function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}

@Concurrent
async function getFile(key: string, context: Context): Promise<ArrayBuffer | undefined> {
  // 读取文件缓存
  let buf = FileCache.getFileCacheByFile(context, key)

  if (buf !== undefined) {
    return buf
  }

  buf = new ArrayBuffer(1024 * 1024)
  // 写文件缓存
  FileCache.saveFileCacheOnlyFile(context, key, buf)
  return buf;
}