package store

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
)

func hashAPIKey(key string) string {
	sum := sha256.Sum256([]byte(key))
	return hex.EncodeToString(sum[:])
}

func generateAPIKeyPlain() (string, string, error) {
	b := make([]byte, 24)
	if _, err := rand.Read(b); err != nil {
		return "", "", err
	}
	plain := "wh_" + hex.EncodeToString(b)
	prefix := plain
	if len(prefix) > 12 {
		prefix = prefix[:12]
	}
	return plain, prefix, nil
}

func (s *Store) ListAPIKeys(userID uint, isAdmin bool) ([]APIKey, error) {
	var keys []APIKey
	q := s.db.Order("id asc")
	if !isAdmin {
		q = q.Where("user_id = ?", userID)
	}
	return keys, q.Find(&keys).Error
}

func (s *Store) CreateAPIKey(name string, userID uint) (*APIKey, string, error) {
	if name == "" {
		return nil, "", errors.New("name required")
	}
	plain, prefix, err := generateAPIKeyPlain()
	if err != nil {
		return nil, "", err
	}
	key := &APIKey{
		Name:      name,
		KeyPrefix: prefix,
		KeyHash:   hashAPIKey(plain),
		UserID:    userID,
		Status:    true,
	}
	if err := s.db.Create(key).Error; err != nil {
		return nil, "", err
	}
	return key, plain, nil
}

func (s *Store) DeleteAPIKey(id uint, userID uint, isAdmin bool) error {
	var key APIKey
	if err := s.db.First(&key, id).Error; err != nil {
		return err
	}
	if !isAdmin && key.UserID != userID {
		return fmt.Errorf("permission denied")
	}
	return s.db.Delete(&APIKey{}, id).Error
}

func (s *Store) ValidateAPIKey(plain string) (*User, error) {
	if plain == "" {
		return nil, errors.New("empty api key")
	}
	hash := hashAPIKey(plain)
	var key APIKey
	if err := s.db.Where("key_hash = ? AND status = ?", hash, true).First(&key).Error; err != nil {
		return nil, errors.New("invalid api key")
	}
	user, err := s.GetUserByID(key.UserID)
	if err != nil {
		return nil, err
	}
	if !user.Status {
		return nil, errors.New("user disabled")
	}
	return user, nil
}
