package cache

import (
	"encoding/json"

	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/fiskerinc/cloud-services/pkg/db/queries"
	"github.com/fiskerinc/cloud-services/pkg/duration"
	"github.com/fiskerinc/cloud-services/pkg/logger"
	"github.com/fiskerinc/cloud-services/pkg/redis"
	"github.com/google/uuid"
	"github.com/pkg/errors"
)

func RetrieveSubscriptionTypesList(client redis.Client, db queries.SubscriptionTypesInterface) ([]common.SubscriptionType, error) {
	data, err := retrieveSubscriptionTypesRedis(client, uuid.Nil)
	if err != nil && !errors.Is(err, redis.ErrInvalidResults) {
		return nil, err
	}
	if data != nil {
		return convertSubTypesList(data)
	}

	items, err := db.Select(&common.SubscriptionType{})
	if err != nil {
		return nil, err
	}
	if len(items) == 0 {
		logger.Warn().Msg("no subscription types")
		return []common.SubscriptionType{}, nil
	}

	for i := range items {
		item := &items[i]
		item.ClearDates()
	}

	err = storeSubscriptionTypesRedis(client, uuid.Nil, items)
	if err != nil {
		return nil, err
	}

	return items, nil
}

func RetrieveSubscriptionType(client redis.Client, db queries.SubscriptionTypesInterface, subtypeID uuid.UUID) (*common.SubscriptionType, error) {
	data, err := retrieveSubscriptionTypesRedis(client, subtypeID)
	if err != nil && !errors.Is(err, redis.ErrInvalidResults) {
		return nil, err
	}
	if data != nil {
		return convertSubType(data)
	}

	items, err := db.Select(&common.SubscriptionType{ID: subtypeID})
	if err != nil {
		return nil, err
	}
	if len(items) == 0 {
		return nil, errors.Errorf("subscription type %v not found", subtypeID)
	}

	err = storeSubscriptionTypesRedis(client, subtypeID, items[0])
	if err != nil {
		return nil, err
	}

	return &items[0], nil
}

func storeSubscriptionTypesRedis(client redis.Client, subtypeID uuid.UUID, data interface{}) error {
	return client.SetCache(redis.SubscriptionTypeListKey(subtypeID), data, duration.Hour)
}

func retrieveSubscriptionTypesRedis(client redis.Client, subtypeID uuid.UUID) ([]byte, error) {
	key := redis.SubscriptionTypeListKey(subtypeID)
	values, err := client.Get(key)
	if err != nil {
		return nil, err
	}
	if values == nil {
		return nil, redis.ErrInvalidResults
	}

	data, ok := values.([]byte)
	if !ok {
		return nil, errors.New("unable to convert to []byte")
	}

	return data, nil
}

func convertSubTypesList(data []byte) ([]common.SubscriptionType, error) {
	result := []common.SubscriptionType{}
	err := json.Unmarshal(data, &result)
	return result, err
}

func convertSubType(data []byte) (*common.SubscriptionType, error) {
	result := common.SubscriptionType{}
	err := json.Unmarshal(data, &result)
	return &result, err
}
