package handler

import (
	"baron-sso-backend/internal/domain"
	"crypto/rand"
	"encoding/binary"
	"testing"
	"unicode"
)

// 정책을 받아 필수 요구사항을 모두 포함하는 비밀번호를 생성한다.
func generatePasswordFromPolicy(policy *domain.PasswordPolicy) string {
	minLen := policy.MinLength
	if minLen < 8 {
		minLen = 12 // 안전한 기본값
	}

	pwd := make([]rune, 0, minLen)

	if policy.Lowercase {
		pwd = append(pwd, 'a')
	}
	if policy.Uppercase {
		pwd = append(pwd, 'B')
	}
	if policy.Number {
		pwd = append(pwd, '3')
	}
	if policy.NonAlphanumeric {
		pwd = append(pwd, '!')
	}

	charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
	for len(pwd) < minLen {
		pwd = append(pwd, rune(charset[randomInt(len(charset))]))
	}

	// 섞어서 예측 가능성을 낮춘다.
	for i := range pwd {
		j := randomInt(len(pwd))
		pwd[i], pwd[j] = pwd[j], pwd[i]
	}
	return string(pwd)
}

func randomInt(n int) int {
	if n <= 0 {
		return 0
	}
	var b [8]byte
	if _, err := rand.Read(b[:]); err != nil {
		return 0
	}
	return int(binary.BigEndian.Uint64(b[:]) % uint64(n))
}

func TestGeneratePasswordUsesNonAlphanumericRequirement(t *testing.T) {
	policy := &domain.PasswordPolicy{
		MinLength:       8,
		Lowercase:       true,
		Uppercase:       true,
		Number:          true,
		NonAlphanumeric: true,
	}

	pwd := generatePasswordFromPolicy(policy)

	if len(pwd) < policy.MinLength {
		t.Fatalf("비밀번호 길이가 정책 최소 길이 미만: got %d, want >= %d", len(pwd), policy.MinLength)
	}

	var hasLower, hasUpper, hasNumber, hasSymbol bool
	for _, r := range pwd {
		switch {
		case unicode.IsLower(r):
			hasLower = true
		case unicode.IsUpper(r):
			hasUpper = true
		case unicode.IsNumber(r):
			hasNumber = true
		case !unicode.IsLetter(r) && !unicode.IsNumber(r):
			hasSymbol = true
		}
	}

	if policy.Lowercase && !hasLower {
		t.Fatalf("소문자 요구사항 미충족: %q", pwd)
	}
	if policy.Uppercase && !hasUpper {
		t.Fatalf("대문자 요구사항 미충족: %q", pwd)
	}
	if policy.Number && !hasNumber {
		t.Fatalf("숫자 요구사항 미충족: %q", pwd)
	}
	if policy.NonAlphanumeric && !hasSymbol {
		t.Fatalf("비영문자 요구사항 미충족: %q", pwd)
	}
}
