import { CacheStorageModule } from '../../modules'

import { contractDbVersion } from '../../../version-contract-db.json'

import { Contract } from '../../interfaces'

interface IPayload<T> {
	key: string
	contract?: Contract
	expirationInSeconds?: number
	init: () => Promise<T>
	unsave?: boolean
}

interface IResponse<T> {
	data: T
	fromCache: boolean
}

export class CacheService {
	private static cacheIsEnabled: boolean = true

	public static async getData<T>(params: IPayload<T>): Promise<IResponse<T>> {
		const chain =
			params.contract !== undefined
				? '' + (await params.contract!.signer?.getChainId())
				: 'public'
		const cacheKey =
			params.key + '_' + contractDbVersion + '_chain_' + chain
		// console.log(chain)
		if (CacheService.cacheIsEnabled) {
			// console.log('CacheService (pre result)')
			const result = await CacheStorageModule.getData<T>(cacheKey)
			// console.log('CacheService (result)', result)

			if (result !== undefined) {
				const response: IResponse<T> = {
					data: result,
					fromCache: true,
				}
				return response
				// console.log('CacheService (cacheKey)', cacheKey)
				// console.log('CacheService (fromCache)', fromCache)
				// console.log('CacheService (result)', { data, fromCache })
			}
		}

		// console.log('CacheService (pre data)')
		const data: T = await params.init()

		// console.log('CacheService (data)', data)

		if (
			data !== undefined &&
			CacheService.cacheIsEnabled &&
			!params.unsave
		) {
			delete (data as unknown as any).unsave
			// console.log('pre CacheStorageModule.addData')
			await CacheStorageModule.addData(
				cacheKey,
				data,
				params.expirationInSeconds,
			)
			// console.log('post CacheStorageModule.addData')
		}
		const response = {
			data,
			fromCache: false,
		}

		return response
	}

	public static async updateData<T>(payload: {
		key: string
		contract: Contract | undefined
		data: T
		expirationInSeconds?: number
		forceToAdd?: boolean
	}): Promise<void> {
		try {
			const chain =
				payload.contract !== undefined
					? '' + (await payload.contract.signer?.getChainId())
					: 'public'
			const cacheKey =
				payload?.key + '_' + contractDbVersion + '_chain_' + chain

			if (!payload?.forceToAdd && CacheService.cacheIsEnabled) {
				await CacheStorageModule.updateData(
					cacheKey,
					payload?.data,
					payload?.expirationInSeconds,
				)
			}

			if (payload?.forceToAdd && CacheService.cacheIsEnabled) {
				await CacheStorageModule.addData(
					cacheKey,
					payload?.data,
					payload?.expirationInSeconds,
				)
			}
		} catch (err: any) {
			console.log('CacheService ERROR (updateData)', err?.message)
		}
	}

	public static async resetData(): Promise<void> {
		try {
			await CacheStorageModule.resetData()
		} catch (err: any) {
			console.log('CacheService ERROR (removeData)', err?.message)
		}
	}
}
