package lib

import (
	"ColdVerify_local/logs"
	"ColdVerify_local/models/Account"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/beego/beego/v2/server/web/context"
	"github.com/nats-io/nats.go"
	"github.com/signintech/gopdf"
	"io/ioutil"
	"log"
	"math"
	"math/rand"
	"os"
	"os/exec"
	"runtime"
	"sort"
	"strconv"
	"strings"
	"time"
	"unicode"
)

var Nats *nats.Conn

type JSONS struct {
	//必须的大写开头
	Code int16
	Msg  string
	Data interface{} // 泛型
}

type JSONSSE struct {
	State int8   // 状态  0 进行中   1 成功    2 失败
	Msg   string // 内容
}

type R_JSONS struct {
	//必须的大写开头
	List      interface{}
	Num       int
	Page      int
	Page_size int
	Pages     []Page_T
}
type R_JSONS_s struct {
	//必须的大写开头
	List      []interface{}
	Num       int
	Page      int
	Page_size int
	Pages     []Page_T
}

type LOG_JSONS struct {
	//必须的大写开头
	Class_1    string
	Class_List interface{}
	List       interface{}
	Num        int
	Page       int
	Page_size  int
	Pages      []Page_T
}

// 获取登录用户uuid
func GetAdminT_Uuid(GetCookie string, GetString string) (string, bool) {
	// 自适应 参数
	User_tokey := GetCookie
	if len(User_tokey) == 0 {
		User_tokey = GetString
	}
	if len(User_tokey) == 0 {
		return "", false
	}
	// 判断 tokey 是否存在
	tokey, is := Account.Read_Tokey(User_tokey)
	if !is {
		return "", false
	}
	log.Println("登录 User_uuid 为：", tokey)
	return tokey, true
}

// func_page 分页   [{3 1} {4 2} {4 3} {4 4} {4 5} {4 6} {4 7} {4 8} {4 9} {5 2}]-
type Page_T struct {
	A int
	V int64
}

func Func_page(Page int64, Page_size int64) (page_t_list []Page_T) {
	if Page > 1 {
		page_t_list = append(page_t_list, Page_T{A: 1, V: Page - 1})
	}
	i := int64(0)
	for aa := int64(1); aa < 5; aa++ {
		if Page-aa <= 0 {
			break
		}
		page_t_list = append(page_t_list, Page_T{A: 2, V: Page - aa})
		i++
	}
	page_t_list = append(page_t_list, Page_T{A: 3, V: Page})

	for aa := int64(1); aa < 10-i; aa++ {
		if Page_size < Page+aa {
			break
		}
		page_t_list = append(page_t_list, Page_T{A: 4, V: Page + aa})
	}
	sort.Slice(page_t_list, func(i, j int) bool {
		if page_t_list[i].V < page_t_list[j].V {
			return true
		}
		return false
	})
	sort.Slice(page_t_list, func(i, j int) bool {
		if page_t_list[i].A < page_t_list[j].A {
			return true
		}
		return false

	})
	if Page < Page_size {
		page_t_list = append(page_t_list, Page_T{A: 5, V: Page + 1})
	}

	return page_t_list
}

func Strval(value interface{}) string {
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}

	return key
}

func To_int(value interface{}) int {
	var key int
	if value == nil {
		return key
	}
	switch value.(type) {
	case float64:
		key = int(value.(float64))
	case float32:
		key = int(value.(float32))
	case int:
		key = int(value.(int))
	case uint:
		key = int(value.(uint))
	case int8:
		key = int(value.(int8))
	case uint8:
		key = int(value.(uint8))
	case int16:
		key = int(value.(int16))
	case uint16:
		key = int(value.(uint16))
	case int32:
		key = int(value.(int32))
	case uint32:
		key = int(value.(uint32))
	case int64:
		key = int(value.(int64))
	case uint64:
		key = int(value.(uint64))
	case string:
		key, _ = strconv.Atoi(value.(string))
	case []byte:
		key, _ = strconv.Atoi(string(value.([]byte)))
	default:
		newValue, _ := json.Marshal(value)
		key, _ = strconv.Atoi(string(newValue))
	}
	return key
}

func To_float32(value interface{}) float32 {
	var key float32
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		key = float32(value.(float64))
	case float32:
		key = float32(value.(float32))
	case int:
		key = float32(value.(int))
	case uint:
		key = float32(value.(uint))
	case int8:
		key = float32(value.(int8))
	case uint8:
		key = float32(value.(uint8))
	case int16:
		key = float32(value.(int16))
	case uint16:
		key = float32(value.(uint16))
	case int32:
		key = float32(value.(int32))
	case uint32:
		key = float32(value.(uint32))
	case int64:
		key = float32(value.(int64))
	case uint64:
		key = float32(value.(uint64))
	case string:
		key_float64, _ := strconv.ParseFloat(value.(string), 32/64)
		key = float32(key_float64)
	case []byte:
		key_float64, _ := strconv.ParseFloat(string(value.([]byte)), 32/64)
		key = float32(key_float64)
	default:
		newValue, _ := json.Marshal(value)
		key_float64, _ := strconv.ParseFloat(string(newValue), 32/64)
		key = float32(key_float64)
	}

	key_float64, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", key), 32/64)
	key = float32(key_float64)

	return key
}

// StringToFloat32 将字符串转换为 float32，支持数字、小数点和负数
func StringToFloat32(s string) (float32, error) {
	cleanedStr := ""
	for i, char := range s {
		// 允许数字、小数点，以及第一个字符是负号
		if unicode.IsDigit(char) || char == '.' || (char == '-' && i == 0) {
			cleanedStr += string(char)
		}
	}

	// 检查字符串是否为空（例如输入是 "abc"）
	if cleanedStr == "" {
		return 0, fmt.Errorf("无效的数字格式: %s", s)
	}

	// 转换为 float32
	f, err := strconv.ParseFloat(cleanedStr, 32)
	if err != nil {
		return 0, fmt.Errorf("转换失败: %v", err)
	}

	return float32(f), nil
}

func To_string(value interface{}) string {
	var key string
	if value == nil {
		return key
	}

	switch value.(type) {
	case float64:
		ft := value.(float64)
		key = strconv.FormatFloat(ft, 'f', -1, 64)
	case float32:
		ft := value.(float32)
		key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
	case int:
		it := value.(int)
		key = strconv.Itoa(it)
	case uint:
		it := value.(uint)
		key = strconv.Itoa(int(it))
	case int8:
		it := value.(int8)
		key = strconv.Itoa(int(it))
	case uint8:
		it := value.(uint8)
		key = strconv.Itoa(int(it))
	case int16:
		it := value.(int16)
		key = strconv.Itoa(int(it))
	case uint16:
		it := value.(uint16)
		key = strconv.Itoa(int(it))
	case int32:
		it := value.(int32)
		key = strconv.Itoa(int(it))
	case uint32:
		it := value.(uint32)
		key = strconv.Itoa(int(it))
	case int64:
		it := value.(int64)
		key = strconv.FormatInt(it, 10)
	case uint64:
		it := value.(uint64)
		key = strconv.FormatUint(it, 10)
	case string:
		key = value.(string)
	case []byte:
		key = string(value.([]byte))
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}
	return key
}

func Random(min, max int) int {
	rand.Seed(time.Now().Unix()) //Seed生成的随机数
	return rand.Intn(max-min) + min
}

// 取文本（字符串）中间
func GetBetweenStr(str, start, end string) string {
	n := strings.Index(str, start)
	if n == -1 {
		n = 0
	} else {
		n = n + len(start) // 增加了else，不加的会把start带上
	}
	str = string([]byte(str)[n:])
	m := strings.Index(str, end)
	if m == -1 {
		m = len(str)
	}
	str = string([]byte(str)[:m])
	return str
}

// getYearMonthToDay 查询指定年份指定月份有多少天
// @params year int 指定年份
// @params month int 指定月份
func GetYearMonthToDay(year int, month int) int {
	// 有31天的月份
	day31 := map[int]bool{
		1:  true,
		3:  true,
		5:  true,
		7:  true,
		8:  true,
		10: true,
		12: true,
	}
	if day31[month] == true {
		return 31
	}
	// 有30天的月份
	day30 := map[int]bool{
		4:  true,
		6:  true,
		9:  true,
		11: true,
	}
	if day30[month] == true {
		return 30
	}
	// 计算是平年还是闰年
	if (year%4 == 0 && year%100 != 0) || year%400 == 0 {
		// 得出2月的天数
		return 29
	}
	// 得出2月的天数
	return 28
}

const (
	AlignLeft   = 4
	AlignCenter = 5
	AlignRight  = 6
)
const (
	ValignTop    = 1
	ValignMiddle = 2
	ValignBottom = 3
)

func RectFillColor(pdf *gopdf.GoPdf,
	text string,
	fontSize int,
	x, y, w, h float64,
	r, g, b uint8,
	align, valign int,
) {

	pdf.SetLineWidth(0.1)
	pdf.SetFillColor(r, g, b) //setup fill color
	pdf.SetLineType("")       // 线条样式
	pdf.RectFromUpperLeftWithStyle(x, y, w, h, "FD")
	pdf.SetFillColor(0, 0, 0)

	if align == AlignCenter {
		textw, _ := pdf.MeasureTextWidth(text)
		x = x + (w / 2) - (textw / 2)
	} else if align == AlignRight {
		textw, _ := pdf.MeasureTextWidth(text)
		x = x + w - textw
	}

	pdf.SetX(x)

	if valign == ValignMiddle {
		y = y + (h / 2) - (float64(fontSize) / 2)
	} else if valign == ValignBottom {
		y = y + h - float64(fontSize)
	}

	pdf.SetY(y)
	pdf.Cell(nil, text)
}

func Command(arg ...string) (result string, err error) {
	name := "/bin/bash"
	c := "-c"
	// 根据系统设定不同的命令name
	if runtime.GOOS == "windows" {
		name = "cmd"
		c = "/C"
	}
	arg = append([]string{c}, arg...)
	cmd := exec.Command(name, arg...)
	//var out bytes.Buffer
	//cmd.Stdout = &out
	var stderr bytes.Buffer
	cmd.Stderr = &stderr
	//创建获取命令输出管道
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		logs.Println("Error:can not obtain stdout pipe for command:%s\n", err)
		return result, err
	}

	//执行命令
	if err = cmd.Start(); err != nil {
		logs.Println("Error:The command is err,", err)
		return result, err
	}

	//读取所有输出
	res, err := ioutil.ReadAll(stdout)
	if err != nil {
		logs.Println("ReadAll Stdout:", err.Error())
		return result, err
	}

	if err = cmd.Wait(); err != nil {
		e := errors.New(fmt.Sprintf("wait:%s:%s", err.Error(), stderr.String()))
		logs.Println(e.Error())
		return result, e
	}

	result = string(res)
	return result, nil
}

func Create_Dir(path string) error {
	_, err := os.Stat(path)
	// 如果返回的错误为nil,说明文件或文件夹存在
	if err == nil {
		return nil
	}
	if err = os.Mkdir(path, 0777); err != nil {
		return err
	}
	return nil
}

// 获取正在运行的函数名
func FuncName() string {
	pc := make([]uintptr, 1)
	runtime.Callers(2, pc)
	f := runtime.FuncForPC(pc[0])
	return f.Name()
}

// 发送 数据
func SseWriteJSON(client *context.Response, msg JSONSSE) error {
	datajson, _ := json.Marshal(msg)
	// Send data to the client
	client.Write(append(append([]byte("data: "), datajson...), []byte("\n\n")...))
	//client.Write([]byte("\n"))
	logs.Println("SseWriteJSON：", string(datajson))
	// Flush the response writer to send the data immediately
	client.Flush()

	return nil
}

// 格式化为保留两位小数的字符串
func To2(number float32) string {

	formatted := fmt.Sprintf("%.2f", number)
	//fmt.Println(formatted) // 输出: 3.14
	return formatted

}

func RoundToDecimal(num float64, decimal int) float64 {
	shift := math.Pow(10, float64(decimal))
	return math.Round(num*shift) / shift
}
