package utils

import (
	"crypto/rand"
	"crypto/rsa"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/redis/go-redis/v9"
	"os"
)

func RandomString(size int, patten string) string {
	buffer, limit := make([]byte, size), len(patten)
	for i := 0; i < size; i++ {
		buffer[i] = patten[RandInt(limit)]
	}
	return string(buffer)
}

func WsEvent(event string, data any) WsMsg {
	return WsMsg{Event: event, Data: data}
}

func WsError(msg string) WsMsg {
	return WsMsg{Event: "_ERROR_", Data: msg}
}

func Success(data any) Response {
	return Response{true, "success", data}
}

func Fail(msg string) Response {
	return Response{false, msg, nil}
}

func ReadConfig(filepath string) Config {
	config := Config{
		Release: false, ServerAddr: "127.0.0.1:3080", TimeFormat: "15:04:05",
		MysqlHost: "127.0.0.1", MysqlPort: 3306, MysqlUser: "wine", MysqlPass: "Wine-Mysql.1000", MysqlDatabase: "wine",
		RedisHost: "127.0.0.1", RedisPort: 6379, RedisPass: "Wine-Redis.1000", RedisDatabase: 0,
	}

	file, err := os.Open(filepath)
	if err != nil {
		return config
	}
	defer func() {
		err = file.Close()
		if err != nil {
		}
	}()

	decoder := json.NewDecoder(file)
	var conf Config
	err = decoder.Decode(&conf)
	if err != nil {
		return config
	}

	return conf
}

func SqlInit(config *Config) {
	Redis = redis.NewClient(&redis.Options{
		Addr:     fmt.Sprintf("%s:%d", config.RedisHost, config.RedisPort),
		Password: config.RedisPass, DB: config.RedisDatabase,
	})

	db, err := sql.Open(
		"mysql",
		fmt.Sprintf(
			"%s:%s@tcp(%s:%d)/%s?loc=Local&charset=utf8&parseTime=true",
			config.MysqlUser, config.MysqlPass, config.MysqlHost, config.MysqlPort, config.MysqlDatabase,
		),
	)
	if err != nil {
		fmt.Println("mysql init failed.")
		os.Exit(-1)
	}
	err = db.Ping()
	if err != nil {
		fmt.Println("mysql connection failed.")
		os.Exit(-1)
	}

	Mysql = db
}

func GenRsaKey() error {
	var err error
	var bytes []byte

	ServerPri, err = rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return err
	}
	bytes, err = MarshalPublicKey(&ServerPri.PublicKey)
	if err != nil {
		return err
	}
	publicBlock := &pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: bytes,
	}
	ClientPub = string(pem.EncodeToMemory(publicBlock))

	return nil
}

func Encrypt(data string) (string, error) {
	return "", nil
}

func Decrypt(data string) (string, error) {
	bytes, err := base64.StdEncoding.DecodeString(data)
	if err != nil {
		return "", err
	}
	bytes, err = rsa.DecryptPKCS1v15(rand.Reader, ServerPri, bytes)
	if err != nil {
		return "", err
	}
	return string(bytes), nil
}

func UnZip(list JsonType) ([]string, []any) {
	var keys []string
	var values []any
	for k, v := range list {
		keys = append(keys, k)
		values = append(values, v)
	}
	return keys, values
}

func SqlFields(names []string) string {
	var res string
	for _, name := range names {
		res += fmt.Sprintf("`%s`=?, ", name)
	}
	ll := len(res)
	if ll > 0 {
		return res[:ll-2]
	}
	return res
}

func AnyTrans(data any, aim any) error {
	tmp, err := json.Marshal(data)
	if err != nil {
		return err
	}
	err = json.Unmarshal(tmp, aim)
	if err != nil {
		return err
	}
	return nil
}
