package utils

import (
	"encoding/base64"
	"fmt"
	"regexp"
)

const (
	Base64Std = iota
	Base64Url
	Base64RawStd
	Base64RawUrl
)

func Base64StdEncode(str interface{}) string {
	return Base64Encode(str, Base64Std)
}

func Base64StdDecode(str interface{}) string {
	return Base64Decode(str, Base64Std)
}

func Base64UrlEncode(str interface{}) string {
	return Base64Encode(str, Base64Url)
}

func Base64UrlDecode(str interface{}) string {
	return Base64Decode(str, Base64Url)
}

func Base64RawStdEncode(str interface{}) string {
	return Base64Encode(str, Base64RawStd)
}

func Base64RawStdDecode(str interface{}) string {
	return Base64Decode(str, Base64RawStd)
}

func Base64RawUrlEncode(str interface{}) string {
	return Base64Encode(str, Base64RawUrl)
}

func Base64RawUrlDecode(str interface{}) string {
	return Base64Decode(str, Base64RawUrl)
}

func Base64Encode(str interface{}, encode int) string {
	newEncode := base64Encode(encode)
	if newEncode == nil {
		return ""
	}
	switch v := str.(type) {
	case string:
		return newEncode.EncodeToString([]byte(v))
	case []byte:
		return newEncode.EncodeToString(v)
	}
	return newEncode.EncodeToString([]byte(fmt.Sprint(str)))
}

func Base64Decode(str interface{}, encode int) string {
	var err error
	var b []byte
	newEncode := base64Encode(encode)
	if newEncode == nil {
		return ""
	}
	switch v := str.(type) {
	case string:
		b, err = newEncode.DecodeString(v)
	case []byte:
		b, err = newEncode.DecodeString(string(v))
	default:
		return ""
	}
	if err != nil {
		return ""
	}
	return string(b)
}

func base64Encode(encode int) *base64.Encoding {
	switch encode {
	case Base64Std:
		return base64.StdEncoding
	case Base64Url:
		return base64.URLEncoding
	case Base64RawStd:
		return base64.RawStdEncoding
	case Base64RawUrl:
		return base64.RawURLEncoding
	default:
		return nil
	}
}

func JudgeBase64(str string) bool {
	pattern := "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$"
	matched, err := regexp.MatchString(pattern, str)
	if err != nil {
		return false
	}
	if !(len(str)%4 == 0 && matched) {
		return false
	}
	unCodeStr, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return false
	}
	tranStr := base64.StdEncoding.EncodeToString(unCodeStr)
	//return str==base64.StdEncoding.EncodeToString(unCodeStr)
	if str == tranStr {
		return true
	}
	return false
}
