package plugins

import (
	"crypto/sha256"
	"fmt"
	"strings"
	"time"
)

type TimerType uint8

const (
	TimerTypePermit TimerType = iota
	TimerTypeCooldown
)

type (
	TimerEntry struct {
		Kind TimerType `json:"kind"`
		Time time.Time `json:"time"`
	}

	TimerStore interface {
		AddCooldown(tt TimerType, limiter, ruleID string, expiry time.Time) error
		InCooldown(tt TimerType, limiter, ruleID string) (bool, error)
		AddPermit(channel, username string) error
		HasPermit(channel, username string) (bool, error)
	}

	testTimerStore struct {
		timers map[string]time.Time
	}
)

var _ TimerStore = (*testTimerStore)(nil)

func newTestTimerStore() *testTimerStore { return &testTimerStore{timers: map[string]time.Time{}} }

// Cooldown timer

func (t *testTimerStore) AddCooldown(tt TimerType, limiter, ruleID string, expiry time.Time) error {
	t.timers[t.getCooldownTimerKey(tt, limiter, ruleID)] = expiry
	return nil
}

func (t *testTimerStore) InCooldown(tt TimerType, limiter, ruleID string) (bool, error) {
	return t.timers[t.getCooldownTimerKey(tt, limiter, ruleID)].After(time.Now()), nil
}

func (testTimerStore) getCooldownTimerKey(tt TimerType, limiter, ruleID string) string {
	h := sha256.New()
	fmt.Fprintf(h, "%d:%s:%s", tt, limiter, ruleID)
	return fmt.Sprintf("sha256:%x", h.Sum(nil))
}

// Permit timer

func (t *testTimerStore) AddPermit(channel, username string) error {
	t.timers[t.getPermitTimerKey(channel, username)] = time.Now().Add(time.Minute)
	return nil
}

func (t *testTimerStore) HasPermit(channel, username string) (bool, error) {
	return t.timers[t.getPermitTimerKey(channel, username)].After(time.Now()), nil
}

func (testTimerStore) getPermitTimerKey(channel, username string) string {
	h := sha256.New()
	fmt.Fprintf(h, "%d:%s:%s", TimerTypePermit, channel, strings.ToLower(strings.TrimLeft(username, "@")))
	return fmt.Sprintf("sha256:%x", h.Sum(nil))
}