package mycommon

import (
	"errors"
	"git.makemake.in/kzkzzzz/mycommon/mylog"
	"log"
	"math/rand/v2"
	"net"
	"os"
	"runtime/debug"
	"sync"
)

func SafeFn(fn func()) {
	defer func() {
		if err := recover(); err != nil {
			mylog.Errorf("panic: %s\n%s", err, string(debug.Stack()))
		}
	}()

	fn()
}

func SafeGo(fn func()) {
	go func() {
		SafeFn(fn)
	}()
}

// RandRange [min, max] 左右均包含
func RandRange(min, max int) int {
	return rand.IntN(max+1-min) + min
}

func RandRangeFloat(min, max float64) float64 {
	return min + rand.Float64()*(max-min+1e-10)
}

var (
	getIpOnce  = &sync.Once{}
	outBoundIp = "127.0.0.1"
)

// GetOutboundIP 获取本机ip
func GetOutboundIP() string {
	getIpOnce.Do(func() {
		conn, err := net.Dial("udp", "223.5.5.5:53")
		if err != nil {
			log.Printf("get outbound ip err: %s", err)
			return
		}
		defer conn.Close()

		localAddr := conn.LocalAddr().(*net.UDPAddr)

		if localAddr.IP != nil {
			outBoundIp = localAddr.IP.String()
		}
	})

	return outBoundIp
}

var (
	getHostNameOnce = &sync.Once{}
	hostName        = "unknown"
)

// GetHostName 获取hostname
func GetHostName() string {
	getHostNameOnce.Do(func() {
		v, err := os.Hostname()
		if err != nil {
			log.Printf("get host name err: %s", err)
			return
		}

		hostName = v
	})

	return hostName
}

func ExistFile(file string) bool {
	_, err := os.Stat(file)
	if err == nil {
		return true
	}

	if errors.Is(err, os.ErrNotExist) {
		return false
	}

	// 其他错误
	return false
}

func UniqueSlice[T comparable](rawSlice []T) []T {
	if len(rawSlice) <= 1 {
		return rawSlice
	}

	uniqueSlice := make([]T, 0, len(rawSlice))
	has := make(map[T]bool, len(rawSlice))
	for _, v := range rawSlice {
		if !has[v] {
			uniqueSlice = append(uniqueSlice, v)
			has[v] = true
		}
	}
	return uniqueSlice
}

// Ptr 获取类型指针
func Ptr[T any](v T) *T {
	return &v
}

func StringPtr(v string) *string {
	if v == "" {
		return nil
	}
	return &v
}

func StringVal(v *string) string {
	if v == nil {
		return ""
	}
	return *v
}
