/// <reference types="../../" />
import * as R from "ramda";
import { log_debug, log_verbose, log_warning } from "./logger";
import { CacheManager } from "./CacheManager";

import {
  getNativeRootPath,
  isAssetCacheEnabled,
  storeFiles,
  collectAssets,
  remapAssetPath,
  fileIsSaved,
} from "@applicaster/zapp-react-native-bridge/OfflineAssets";
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";

export async function getLayoutAssets({
  layout,
  pluginConfigurations,
  cellStyles,
}) {
  const nativeRootPath = await getNativeRootPath();

  const layoutAssets: FilesList = collectAssets(
    layout,
    nativeRootPath,
    "rivers",
    []
  );

  const pluginAssets: FilesList = collectAssets(
    pluginConfigurations,
    nativeRootPath,
    "plugins",
    []
  );

  const cellAssets: FilesList = collectAssets(
    cellStyles,
    nativeRootPath,
    "cellStyles",
    []
  );

  // @ts-ignore
  const assetFiles: FilesList = R.compose(
    R.sortWith([R.ascend(R.prop("file"))]),
    R.uniqBy(R.prop("file")),
    // @ts-ignore
    R.flatten
    // @ts-ignore
  )([layoutAssets, pluginAssets, cellAssets]);

  return { assetFiles, layoutAssets, pluginAssets, cellAssets };
}

export async function cacheAssets({
  layout,
  pluginConfigurations,
  cellStyles,
}: CacheAssetsArgs) {
  if (!isAssetCacheEnabled() || isTV()) {
    log_debug(
      "cacheAssets:" + !isAssetCacheEnabled()
        ? "Asset caching is disabled"
        : "Running on TV platform" + "skipping asset caching"
    );

    return {
      layout,
      pluginConfigurations,
      cellStyles,
    };
  }

  const layoutId = layout?.id;

  if (!layoutId) {
    log_warning("cacheAssets: layout id is undefined, cannot cache assets");

    return {
      layout,
      pluginConfigurations,
      cellStyles,
    };
  }

  const time = performance.now();

  try {
    const { assetFiles, cellAssets, pluginAssets, layoutAssets } =
      await getLayoutAssets({
        layout,
        pluginConfigurations,
        cellStyles,
      });

    log_debug(`cacheAssets: getting layout assets: 
     assetFilesCount: ${assetFiles.length},
     cellAssets: ${cellAssets.length},
     pluginAssets: ${pluginAssets.length},
     layoutAssets: ${layoutAssets?.length}`);

    const { removedFiles, newFiles, unchangedFiles } =
      await CacheManager.instance.getFilesToCache(layoutId, assetFiles);

    log_debug(`cacheAssets: getting files to cache for layoutId: ${layoutId},
     removedFiles: ${removedFiles?.length}, 
     newFiles: ${newFiles.length},
     unchangedFiles: ${unchangedFiles.length}`);

    const needsCacheUpdate = removedFiles?.length > 0 || newFiles?.length > 0;
    let newCacheState = unchangedFiles;

    if (removedFiles?.length > 0) {
      await CacheManager.instance.clearCache(removedFiles);

      log_debug(`cacheAssets: removed files: ${removedFiles.length}`);
    }

    if (newFiles?.length > 0) {
      // TODO: Check that we are online

      const result: StoredFilesResult = await storeFiles(newFiles);

      const cachedFiles = R.filter(fileIsSaved(result), assetFiles);

      newCacheState = cachedFiles.concat(unchangedFiles);

      log_debug(
        `cacheAssets: saved new files, cashedFiles: ${cachedFiles.length}`
      );
    }

    if (needsCacheUpdate && newCacheState) {
      await CacheManager.instance.saveCacheData(layoutId, newCacheState);

      log_debug(
        `cacheAssets: saving caching data for layoutId: ${layoutId}, cashedFiles: ${newCacheState.length}`
      );
    }

    const urlFileMap: { [key: string]: string } = {};

    newCacheState.forEach(({ file, url }) => (urlFileMap[url] = file));

    const updatedLayout = remapAssetPath(
      layoutAssets,
      layout,
      urlFileMap,
      "layoutAssets"
    );

    const updatedPluginConfigurations = remapAssetPath(
      pluginAssets,
      pluginConfigurations,
      urlFileMap,
      "pluginAssets"
    );

    const updatedCellStyles = remapAssetPath(
      cellAssets,
      cellStyles,
      urlFileMap,
      "cellStyles"
    );

    return {
      layout: updatedLayout,
      pluginConfigurations: updatedPluginConfigurations,
      cellStyles: updatedCellStyles,
    };
  } catch (error) {
    log_warning(`cacheAssets: Error caching assets, message: ${error.message}`);

    return { layout, pluginConfigurations, cellStyles };
  } finally {
    log_verbose(
      `cacheAssets: caching assets took ${performance.now() - time} ms`
    );
  }
}
