package cachemap

import (
	"context"
	"time"
)

func CacheFunc11[K1 comparable, V1 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1) V1) func(K1) V1 {
	cacheMap := NewSelfCleaning[K1, V1](ctx, cacheDuration, cleanUpInterval)
	return func(key K1) V1 {
		if value, ok := cacheMap.Get(key); ok {
			return value
		}

		value := f(key)
		cacheMap.Put(key, value)
		return value
	}
}

func CacheFunc12[K1 comparable, V1, V2 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1) (V1, V2)) func(K1) (V1, V2) {
	type Value struct {
		Value1 V1
		Value2 V2
	}

	cacheMap := NewSelfCleaning[K1, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key K1) (V1, V2) {
		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2
		}

		value1, value2 := f(key)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
		})
		return value1, value2
	}
}

func CacheFunc13[K1 comparable, V1, V2, V3 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1) (V1, V2, V3)) func(K1) (V1, V2, V3) {
	type Value struct {
		Value1 V1
		Value2 V2
		Value3 V3
	}

	cacheMap := NewSelfCleaning[K1, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key K1) (V1, V2, V3) {
		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2, value.Value3
		}

		value1, value2, value3 := f(key)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
			Value3: value3,
		})
		return value1, value2, value3
	}
}

func CacheFunc14[K1 comparable, V1, V2, V3, V4 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1) (V1, V2, V3, V4)) func(K1) (V1, V2, V3, V4) {
	type Value struct {
		Value1 V1
		Value2 V2
		Value3 V3
		Value4 V4
	}

	cacheMap := NewSelfCleaning[K1, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key K1) (V1, V2, V3, V4) {
		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2, value.Value3, value.Value4
		}

		value1, value2, value3, value4 := f(key)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
			Value3: value3,
			Value4: value4,
		})
		return value1, value2, value3, value4
	}
}

func CacheFunc21[K1, K2 comparable, V1 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2) V1) func(K1, K2) V1 {
	type Key struct {
		Key1 K1
		Key2 K2
	}

	cacheMap := NewSelfCleaning[Key, V1](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2) V1 {
		key := Key{Key1: key1, Key2: key2}

		if value, ok := cacheMap.Get(key); ok {
			return value
		}

		value := f(key1, key2)
		cacheMap.Put(key, value)
		return value
	}
}

func CacheFunc22[K1, K2 comparable, V1, V2 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2) (V1, V2)) func(K1, K2) (V1, V2) {
	type Key struct {
		Key1 K1
		Key2 K2
	}

	type Value struct {
		Value1 V1
		Value2 V2
	}

	cacheMap := NewSelfCleaning[Key, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2) (V1, V2) {
		key := Key{Key1: key1, Key2: key2}

		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2
		}

		value1, value2 := f(key1, key2)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
		})
		return value1, value2
	}
}

func CacheFunc23[K1, K2 comparable, V1, V2, V3 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2) (V1, V2, V3)) func(K1, K2) (V1, V2, V3) {
	type Key struct {
		Key1 K1
		Key2 K2
	}

	type Value struct {
		Value1 V1
		Value2 V2
		Value3 V3
	}

	cacheMap := NewSelfCleaning[Key, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2) (V1, V2, V3) {
		key := Key{Key1: key1, Key2: key2}

		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2, value.Value3
		}

		value1, value2, value3 := f(key1, key2)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
			Value3: value3,
		})
		return value1, value2, value3
	}
}

func CacheFunc24[K1, K2 comparable, V1, V2, V3, V4 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2) (V1, V2, V3, V4)) func(K1, K2) (V1, V2, V3, V4) {
	type Key struct {
		Key1 K1
		Key2 K2
	}

	type Value struct {
		Value1 V1
		Value2 V2
		Value3 V3
		Value4 V4
	}

	cacheMap := NewSelfCleaning[Key, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2) (V1, V2, V3, V4) {
		key := Key{Key1: key1, Key2: key2}

		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2, value.Value3, value.Value4
		}

		value1, value2, value3, value4 := f(key1, key2)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
			Value3: value3,
			Value4: value4,
		})
		return value1, value2, value3, value4
	}
}

func CacheFunc31[K1, K2, K3 comparable, V1 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2, K3) V1) func(K1, K2, K3) V1 {
	type Key struct {
		Key1 K1
		Key2 K2
		Key3 K3
	}

	cacheMap := NewSelfCleaning[Key, V1](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2, key3 K3) V1 {
		key := Key{Key1: key1, Key2: key2, Key3: key3}

		if value, ok := cacheMap.Get(key); ok {
			return value
		}

		value := f(key1, key2, key3)
		cacheMap.Put(key, value)
		return value
	}
}

func CacheFunc32[K1, K2, K3 comparable, V1, V2 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2, K3) (V1, V2)) func(K1, K2, K3) (V1, V2) {
	type Key struct {
		Key1 K1
		Key2 K2
		Key3 K3
	}

	type Value struct {
		Value1 V1
		Value2 V2
	}

	cacheMap := NewSelfCleaning[Key, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2, key3 K3) (V1, V2) {
		key := Key{Key1: key1, Key2: key2, Key3: key3}

		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2
		}

		value1, value2 := f(key1, key2, key3)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
		})
		return value1, value2
	}
}

func CacheFunc33[K1, K2, K3 comparable, V1, V2, V3 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2, K3) (V1, V2, V3)) func(K1, K2, K3) (V1, V2, V3) {
	type Key struct {
		Key1 K1
		Key2 K2
		Key3 K3
	}

	type Value struct {
		Value1 V1
		Value2 V2
		Value3 V3
	}

	cacheMap := NewSelfCleaning[Key, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2, key3 K3) (V1, V2, V3) {
		key := Key{Key1: key1, Key2: key2, Key3: key3}

		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2, value.Value3
		}

		value1, value2, value3 := f(key1, key2, key3)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
			Value3: value3,
		})
		return value1, value2, value3
	}
}

func CacheFunc34[K1, K2, K3 comparable, V1, V2, V3, V4 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2, K3) (V1, V2, V3, V4)) func(K1, K2, K3) (V1, V2, V3, V4) {
	type Key struct {
		Key1 K1
		Key2 K2
		Key3 K3
	}

	type Value struct {
		Value1 V1
		Value2 V2
		Value3 V3
		Value4 V4
	}

	cacheMap := NewSelfCleaning[Key, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2, key3 K3) (V1, V2, V3, V4) {
		key := Key{Key1: key1, Key2: key2, Key3: key3}

		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2, value.Value3, value.Value4
		}

		value1, value2, value3, value4 := f(key1, key2, key3)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
			Value3: value3,
			Value4: value4,
		})
		return value1, value2, value3, value4
	}
}

func CacheFunc41[K1, K2, K3, K4 comparable, V1 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2, K3, K4) V1) func(K1, K2, K3, K4) V1 {
	type Key struct {
		Key1 K1
		Key2 K2
		Key3 K3
		Key4 K4
	}

	cacheMap := NewSelfCleaning[Key, V1](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2, key3 K3, key4 K4) V1 {
		key := Key{Key1: key1, Key2: key2, Key3: key3, Key4: key4}

		if value, ok := cacheMap.Get(key); ok {
			return value
		}

		value := f(key1, key2, key3, key4)
		cacheMap.Put(key, value)
		return value
	}
}

func CacheFunc42[K1, K2, K3, K4 comparable, V1, V2 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2, K3, K4) (V1, V2)) func(K1, K2, K3, K4) (V1, V2) {
	type Key struct {
		Key1 K1
		Key2 K2
		Key3 K3
		Key4 K4
	}

	type Value struct {
		Value1 V1
		Value2 V2
	}

	cacheMap := NewSelfCleaning[Key, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2, key3 K3, key4 K4) (V1, V2) {
		key := Key{Key1: key1, Key2: key2, Key3: key3, Key4: key4}

		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2
		}

		value1, value2 := f(key1, key2, key3, key4)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
		})
		return value1, value2
	}
}

func CacheFunc43[K1, K2, K3, K4 comparable, V1, V2, V3 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2, K3, K4) (V1, V2, V3)) func(K1, K2, K3, K4) (V1, V2, V3) {
	type Key struct {
		Key1 K1
		Key2 K2
		Key3 K3
		Key4 K4
	}

	type Value struct {
		Value1 V1
		Value2 V2
		Value3 V3
	}

	cacheMap := NewSelfCleaning[Key, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2, key3 K3, key4 K4) (V1, V2, V3) {
		key := Key{Key1: key1, Key2: key2, Key3: key3, Key4: key4}

		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2, value.Value3
		}

		value1, value2, value3 := f(key1, key2, key3, key4)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
			Value3: value3,
		})
		return value1, value2, value3
	}
}

func CacheFunc44[K1, K2, K3, K4 comparable, V1, V2, V3, V4 any](ctx context.Context, cacheDuration, cleanUpInterval time.Duration, f func(K1, K2, K3, K4) (V1, V2, V3, V4)) func(K1, K2, K3, K4) (V1, V2, V3, V4) {
	type Key struct {
		Key1 K1
		Key2 K2
		Key3 K3
		Key4 K4
	}

	type Value struct {
		Value1 V1
		Value2 V2
		Value3 V3
		Value4 V4
	}

	cacheMap := NewSelfCleaning[Key, Value](ctx, cacheDuration, cleanUpInterval)
	return func(key1 K1, key2 K2, key3 K3, key4 K4) (V1, V2, V3, V4) {
		key := Key{Key1: key1, Key2: key2, Key3: key3, Key4: key4}

		if value, ok := cacheMap.Get(key); ok {
			return value.Value1, value.Value2, value.Value3, value.Value4
		}

		value1, value2, value3, value4 := f(key1, key2, key3, key4)
		cacheMap.Put(key, Value{
			Value1: value1,
			Value2: value2,
			Value3: value3,
			Value4: value4,
		})
		return value1, value2, value3, value4
	}
}