import { type CacheTime, type DataCache } from "@/services/dataCache/Cache"
import { cacheLogger } from "@/services/dataCache/logger"

import {
  type CacheOrGetOptions,
  shouldGetFromCache,
} from "../../cacheOrGetOptions"
import { get } from "./get"
import { set } from "./set"

export const cacheOrGet: DataCache["cacheOrGet"] = async <T>(
  key: string | string[],
  callback: (overrideTTL?: (cacheTime: CacheTime) => void) => Promise<T>,
  ttl: CacheTime,
  opts?: CacheOrGetOptions
): Promise<T> => {
  if (Array.isArray(key)) {
    key = key.join("-")
  }

  let realTTL = ttl
  const overrideTTL = function (cacheTime: CacheTime) {
    realTTL = cacheTime
  }

  let cached: Awaited<T> | undefined = undefined
  if (shouldGetFromCache(opts)) {
    cached = await get(key)
    if (cached) {
      return cached
    }

    cacheLogger.debug(`Miss for key '${key}'`)
  }

  try {
    const data = await callback(overrideTTL)
    await set(key, data, realTTL)

    return data
  } catch (e) {
    cacheLogger.error(
      `Error while fetching data for key '${key}', avoid caching`,
      e
    )
    throw e
  }
}
