package textutil

import (
	"encoding/hex"
	"errors"
	"html"
	"math/rand/v2"
	"regexp"
	"strings"
)

const (
	// Alpha - латинские буквы в нижнем регистре
	Alpha = "abcdefghijklmnopqrstuvwxyz"
	// AlphaUpper - латинские буквы в верхнем регистре
	AlphaUpper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
	// Alpha52 - латинские буквы в верхнем и нижнем регистре
	Alpha52 = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
	// Hex - hex символы в нижнем регистре
	Hex = "abcdef0123456789"
	// HexUpper - hex символы в верхнем регистре
	HexUpper = "ABCDEF0123456789"
	// HumanFriendly - латинские буквы в нижнем регистре (без l, o, i, j) и цифры (без 0, 1)
	HumanFriendly = "abcdefghkmnpqrstuvwxyz23456789" // 1 l, 0 o, j
	// AlphaDigit - латинские буквы в нижнем регистре и цифры
	AlphaDigit = "abcdefghijklmnopqrstuvwxyz0123456789"
	// Alpha52Digit - все латинские буквы в верхнем и нижнем регистре, цифры
	Alpha52Digit = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789"
)

func RandomString(chars string, size int) string {
	if size <= 0 || len(chars) == 0 {
		return ""
	}
	var sb strings.Builder
	sb.Grow(size)
	for i := 0; i < size; i++ {
		// rand.IntN з math/rand/v2 works faster and using automatic seed
		idx := rand.IntN(len(chars))
		sb.WriteByte(chars[idx])
	}

	return sb.String()
}

func IsAlphaDigitsOnly(str string) bool {
	for _, c := range str {
		if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') {
			// ok
		} else {
			return false
		}
	}
	return true
}

func ParseHex(str string) ([]byte, error) {
	normalized := strings.Join(strings.Split(str, " "), "")
	return hex.DecodeString(normalized)
}

func HexToByte(s string) (_ byte, err error) {
	buf, err := hex.DecodeString(s)
	if err != nil {
		return
	}
	if len(buf) != 1 {
		err = errors.New("hex string longer than 1 byte")
		return
	}
	return buf[0], nil
}

func IsValidIMEI(imei string) bool {
	if len(imei) != 15 {
		return false
	}
	for _, digit := range imei {
		switch digit {
		case '1', '2', '3', '4', '5', '6', '7', '8', '9', '0':
			// pass
		default:
			return false
		}
	}
	return true
}

var (
	reWhitespaces = regexp.MustCompile(`\s+`) // \s	whitespace [\t\n\f\r ]
	reNewlines    = regexp.MustCompile(`(?i)<(br|p|li)\s*/?>`)
	reHTMLTag     = regexp.MustCompile(`</?[a-zA-Z][^>]*>`)
)

// NormalizeWhitespaces - удаляет whitespaces по краям строки.
// Cерии whitespaces [\t\n\f\r ] заменяет на 1 пробел.
func NormalizeWhitespaces(s string) string {
	return reWhitespaces.ReplaceAllString(strings.TrimSpace(s), " ")
}

// StripHTML - delete HTML tags, replace <br>, <p>, <li> to \n
func StripHTML(str string) string {
	str = reNewlines.ReplaceAllString(str, "\n")
	str = reHTMLTag.ReplaceAllLiteralString(str, "")
	// &nbsp; або &amp;
	str = html.UnescapeString(str)
	return str
}
