/*
 * Copyright 2026 Oleg Borodin <onborodin@gmail.com>
 */
package auxpwd

import (
	"crypto/sha256"
	"crypto/sha512"
	"encoding/hex"
	"fmt"
	"math/rand"
	"strings"
	"time"
)

var rnd *rand.Rand

const (
	sha256Prefix = "sha256pwd"
	sha512Prefix = "sha512pwd"
	saltSize     = 16
)

func init() {
	src := rand.NewSource(time.Now().UnixNano())
	rnd = rand.New(src)
}

func MakeSHA256Hash(passwd []byte) string {
	var res string
	salt := hex.EncodeToString(randomBytes(saltSize))
	passwdString := hex.EncodeToString(passwd)
	passwdString = fmt.Sprintf("%s%s", passwdString, salt)

	hasher := sha256.New()
	hasher.Write([]byte(passwdString))
	checksum := hex.EncodeToString(hasher.Sum(nil))

	res = fmt.Sprintf("%s:%s:%s", sha256Prefix, salt, checksum)
	return res
}

func MakeSHA512Hash(passwd []byte) string {
	var res string
	salt := hex.EncodeToString(randomBytes(saltSize))
	passwdString := hex.EncodeToString(passwd)
	passwdString = fmt.Sprintf("%s%s", passwdString, salt)

	hasher := sha512.New()
	hasher.Write([]byte(passwdString))
	checksum := hex.EncodeToString(hasher.Sum(nil))

	res = fmt.Sprintf("%s:%s:%s", sha512Prefix, salt, checksum)
	return res
}

func PasswordMatch(passwd []byte, hash string) bool {
	hashComponents := strings.Split(hash, ":")
	if len(hashComponents) != 3 {
		return false
	}
	method := hashComponents[0]
	salt := hashComponents[1]
	controlChecksum := hashComponents[2]

	switch method {
	case sha256Prefix:
		passwdString := hex.EncodeToString(passwd)
		passwdString = fmt.Sprintf("%s%s", passwdString, salt)
		hasher := sha256.New()
		hasher.Write([]byte(passwdString))
		checksum := hex.EncodeToString(hasher.Sum(nil))
		if checksum != controlChecksum {
			return false
		}
	case sha512Prefix:
		passwdString := hex.EncodeToString(passwd)
		passwdString = fmt.Sprintf("%s%s", passwdString, salt)
		hasher := sha512.New()
		hasher.Write([]byte(passwdString))
		checksum := hex.EncodeToString(hasher.Sum(nil))
		if checksum != controlChecksum {
			return false
		}
	default:
		return false
	}
	return true
}

func randomString(n int) string {
	const letters = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	arr := make([]byte, n)
	lettersArrayLen := len(letters)
	for i := range arr {
		arr[i] = letters[rnd.Intn(lettersArrayLen)]
	}
	return string(arr)
}

func randomBytes(n int) []byte {
	arr := make([]byte, n)
	for i := range arr {
		arr[i] = byte(rnd.Intn(256) & 0xFF)
	}
	return arr
}
