package state

import (
	"crypto/rand"
	"crypto/sha256"
	"crypto/subtle"
	"encoding/hex"
	"fmt"
	"sort"
	"strings"
	"time"
	"unicode"
)

func randomHex(bytes int) string {
	buf := make([]byte, bytes)
	_, _ = rand.Read(buf)
	return hex.EncodeToString(buf)
}

func newUUIDv4() string {
	buf := make([]byte, 16)
	_, _ = rand.Read(buf)
	buf[6] = (buf[6] & 0x0f) | 0x40
	buf[8] = (buf[8] & 0x3f) | 0x80

	return fmt.Sprintf("%x-%x-%x-%x-%x", buf[0:4], buf[4:6], buf[6:8], buf[8:10], buf[10:16])
}

func normalizeName(input string, max int) string {
	trimmed := strings.TrimSpace(input)
	if trimmed == "" {
		return ""
	}

	builder := strings.Builder{}
	for _, r := range trimmed {
		if r == '\n' || r == '\r' || r == '\t' {
			continue
		}
		if unicode.IsPrint(r) {
			builder.WriteRune(r)
		}
		if builder.Len() >= max {
			break
		}
	}
	return strings.TrimSpace(builder.String())
}

func normalizeCard(input string) string {
	return normalizeName(input, 8)
}

func hashPassword(password, salt string) string {
	h := sha256.Sum256([]byte(salt + ":" + password))
	return hex.EncodeToString(h[:])
}

func passwordMatches(password, salt, expectedHash string) bool {
	computed := hashPassword(password, salt)
	return subtle.ConstantTimeCompare([]byte(computed), []byte(expectedHash)) == 1
}

func secureTokenMatches(expected, provided string) bool {
	if expected == "" || provided == "" || len(expected) != len(provided) {
		return false
	}
	return subtle.ConstantTimeCompare([]byte(expected), []byte(provided)) == 1
}

func nowUTC() time.Time {
	return time.Now().UTC()
}

func sortParticipants(participants map[string]*Participant) []*Participant {
	list := make([]*Participant, 0, len(participants))
	for _, participant := range participants {
		list = append(list, participant)
	}

	sort.SliceStable(list, func(i, j int) bool {
		if list[i].JoinedAt.Equal(list[j].JoinedAt) {
			return list[i].Username < list[j].Username
		}
		return list[i].JoinedAt.Before(list[j].JoinedAt)
	})

	return list
}
