package store

import "github.uio.no/torjus/apiary/models"

type CachingStore struct {
	backend LoginAttemptStore

	totalStatsCache    []StatsResult
	usernameQueryCache map[string][]models.LoginAttempt
	passwordQueryCache map[string][]models.LoginAttempt
	ipQueryCache       map[string][]models.LoginAttempt
}

func NewCachingStore(backend LoginAttemptStore) *CachingStore {
	return &CachingStore{
		backend:            backend,
		usernameQueryCache: make(map[string][]models.LoginAttempt),
		passwordQueryCache: make(map[string][]models.LoginAttempt),
		ipQueryCache:       make(map[string][]models.LoginAttempt),
	}
}

func (s *CachingStore) AddAttempt(l *models.LoginAttempt) error {
	s.totalStatsCache = nil
	delete(s.ipQueryCache, l.RemoteIP.String())
	delete(s.passwordQueryCache, l.Password)
	delete(s.usernameQueryCache, l.Username)
	return s.backend.AddAttempt(l)
}

func (s *CachingStore) All() ([]models.LoginAttempt, error) {
	return s.backend.All()
}

func (s *CachingStore) Stats(statType LoginStats, limit int) ([]StatsResult, error) {
	// Only cache totals for now, as they are the most queried
	if statType == LoginStatsTotals {
		if s.totalStatsCache != nil {
			return s.totalStatsCache, nil
		}
		stats, err := s.backend.Stats(statType, limit)
		if err != nil {
			return stats, err
		}
		s.totalStatsCache = stats

		return stats, err
	}

	// TODO: Maybe cache the default limits

	return s.backend.Stats(statType, limit)
}

func (s *CachingStore) Query(query AttemptQuery) ([]models.LoginAttempt, error) {
	switch query.QueryType {
	case AttemptQueryTypeIP:
		if attempts, ok := s.ipQueryCache[query.Query]; ok {
			return attempts, nil
		}
	case AttemptQueryTypePassword:
		if attempts, ok := s.passwordQueryCache[query.Query]; ok {
			return attempts, nil
		}
	case AttemptQueryTypeUsername:
		if attempts, ok := s.usernameQueryCache[query.Query]; ok {
			return attempts, nil
		}
	}
	attempts, err := s.backend.Query(query)
	if err != nil {
		return attempts, err
	}

	switch query.QueryType {
	case AttemptQueryTypeIP:
		s.ipQueryCache[query.Query] = attempts
	case AttemptQueryTypeUsername:
		s.ipQueryCache[query.Query] = attempts
	case AttemptQueryTypePassword:
		s.ipQueryCache[query.Query] = attempts
	}

	return attempts, err
}
