package store

import (
	"context"
	"sync"
	"time"

	"github.com/google/uuid"
)

// MemUserRepository 基于内存的 UserRepository 实现（测试用）。
type MemUserRepository struct {
	mu           sync.RWMutex
	users        map[string]*User       // id -> user
	byUsername   map[string]string       // username -> id
	refreshTokens map[string]string      // tokenHash -> userID
	tokenExpiry  map[string]time.Time    // tokenHash -> expiresAt
}

// NewMemUserRepository 创建 MemUserRepository。
func NewMemUserRepository() *MemUserRepository {
	return &MemUserRepository{
		users:        make(map[string]*User),
		byUsername:   make(map[string]string),
		refreshTokens: make(map[string]string),
		tokenExpiry:  make(map[string]time.Time),
	}
}

func (r *MemUserRepository) Create(_ context.Context, username, passwordHash string) (string, error) {
	r.mu.Lock()
	defer r.mu.Unlock()

	if _, exists := r.byUsername[username]; exists {
		return "", ErrUsernameTaken
	}

	id := uuid.New().String()
	now := time.Now()
	user := &User{
		ID:           id,
		Username:     username,
		PasswordHash: passwordHash,
		CreatedAt:    now,
		UpdatedAt:    now,
	}
	r.users[id] = user
	r.byUsername[username] = id
	return id, nil
}

func (r *MemUserRepository) FindByUsername(_ context.Context, username string) (*User, error) {
	r.mu.RLock()
	defer r.mu.RUnlock()

	id, ok := r.byUsername[username]
	if !ok {
		return nil, ErrUserNotFound
	}
	u := r.users[id]
	copy := *u
	return &copy, nil
}

func (r *MemUserRepository) FindByID(_ context.Context, id string) (*User, error) {
	r.mu.RLock()
	defer r.mu.RUnlock()

	u, ok := r.users[id]
	if !ok {
		return nil, ErrUserNotFound
	}
	copy := *u
	return &copy, nil
}

func (r *MemUserRepository) SaveRefreshToken(_ context.Context, userID, tokenHash string, expiresAt time.Time) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	r.refreshTokens[tokenHash] = userID
	r.tokenExpiry[tokenHash] = expiresAt
	return nil
}

func (r *MemUserRepository) FindRefreshToken(_ context.Context, tokenHash string) (string, error) {
	r.mu.RLock()
	defer r.mu.RUnlock()

	userID, ok := r.refreshTokens[tokenHash]
	if !ok {
		return "", ErrRefreshTokenNotFound
	}
	if time.Now().After(r.tokenExpiry[tokenHash]) {
		return "", ErrRefreshTokenNotFound
	}
	return userID, nil
}

func (r *MemUserRepository) DeleteRefreshToken(_ context.Context, tokenHash string) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	delete(r.refreshTokens, tokenHash)
	delete(r.tokenExpiry, tokenHash)
	return nil
}

func (r *MemUserRepository) DeleteUserRefreshTokens(_ context.Context, userID string) error {
	r.mu.Lock()
	defer r.mu.Unlock()

	for hash, uid := range r.refreshTokens {
		if uid == userID {
			delete(r.refreshTokens, hash)
			delete(r.tokenExpiry, hash)
		}
	}
	return nil
}
