package utils

import (
	
	
	
	
	
	
	
	
)

var gormSourceDir string

func init() {
	, , ,  := runtime.Caller(0)
	// compatible solution to get gorm source directory with various operating systems
	gormSourceDir = sourceDir()
}

func sourceDir( string) string {
	 := filepath.Dir()
	 = filepath.Dir()

	 := filepath.Dir()
	if filepath.Base() != "gorm.io" {
		 = 
	}
	return filepath.ToSlash() + "/"
}

// CallerFrame retrieves the first relevant stack frame outside of GORM's internal implementation files.
// It skips:
//   - GORM's core source files (identified by gormSourceDir prefix)
//   - Exclude test files (*_test.go)
//   - go-gorm/gen's Generated files (*.gen.go)
func () runtime.Frame {
	 := [13]uintptr{}
	// the third caller usually from gorm internal
	 := runtime.Callers(3, [:])
	 := runtime.CallersFrames([:])
	for  := 0;  < ; ++ {
		// second return value is "more", not "ok"
		,  := .Next()
		if (!strings.HasPrefix(.File, gormSourceDir) ||
			strings.HasSuffix(.File, "_test.go")) && !strings.HasSuffix(.File, ".gen.go") {
			return 
		}
	}

	return runtime.Frame{}
}

// FileWithLineNum return the file name and line number of the current file
func () string {
	 := CallerFrame()
	if .PC != 0 {
		return string(strconv.AppendInt(append([]byte(.File), ':'), int64(.Line), 10))
	}

	return ""
}

func ( rune) bool {
	return !unicode.IsLetter() && !unicode.IsNumber() &&  != '.' &&  != '*' &&  != '_' &&  != '$' &&  != '@'
}

// CheckTruth check string true or not
func ( ...string) bool {
	for ,  := range  {
		if  != "" && !strings.EqualFold(, "false") {
			return true
		}
	}
	return false
}

func ( ...interface{}) string {
	 := make([]string, len())

	for ,  := range  {
		if ,  := .(driver.Valuer);  {
			, _ = .Value()
		}

		switch v := .(type) {
		case string:
			[] = 
		case []byte:
			[] = string()
		case uint:
			[] = strconv.FormatUint(uint64(), 10)
		default:
			[] = "nil"
			 := reflect.ValueOf()
			if .IsValid() && !.IsZero() {
				[] = fmt.Sprint(reflect.Indirect().Interface())
			}
		}
	}

	return strings.Join(, "_")
}

func ( []string,  string) bool {
	for ,  := range  {
		if  ==  {
			return true
		}
	}
	return false
}

func (,  interface{}) bool {
	if reflect.DeepEqual(, ) {
		return true
	}
	if  == nil ||  == nil {
		return false
	}

	 := reflect.ValueOf()
	 := reflect.ValueOf()
	if .Kind() == reflect.Ptr && .IsNil() ||
		.Kind() == reflect.Ptr && .IsNil() {
		return false
	}

	if ,  := .(driver.Valuer);  {
		, _ = .Value()
	}
	if ,  := .(driver.Valuer);  {
		, _ = .Value()
	}
	return reflect.DeepEqual(, )
}

func ( interface{}) string {
	switch v := .(type) {
	case string:
		return 
	case int:
		return strconv.FormatInt(int64(), 10)
	case int8:
		return strconv.FormatInt(int64(), 10)
	case int16:
		return strconv.FormatInt(int64(), 10)
	case int32:
		return strconv.FormatInt(int64(), 10)
	case int64:
		return strconv.FormatInt(, 10)
	case uint:
		return strconv.FormatUint(uint64(), 10)
	case uint8:
		return strconv.FormatUint(uint64(), 10)
	case uint16:
		return strconv.FormatUint(uint64(), 10)
	case uint32:
		return strconv.FormatUint(uint64(), 10)
	case uint64:
		return strconv.FormatUint(, 10)
	}
	return ""
}

const nestedRelationSplit = "__"

// NestedRelationName nested relationships like `Manager__Company`
func (,  string) string {
	return  + nestedRelationSplit + 
}

// SplitNestedRelationName Split nested relationships to `[]string{"Manager","Company"}`
func ( string) []string {
	return strings.Split(, nestedRelationSplit)
}

// JoinNestedRelationNames nested relationships like `Manager__Company`
func ( []string) string {
	return strings.Join(, nestedRelationSplit)
}

// RTrimSlice Right trims the given slice by given length
func [ any]( [],  int) [] {
	if  >= len() { // trimLen greater than slice len means fully sliced
		return [:0]
	}
	if  < 0 { // negative trimLen is ignored
		return [:]
	}
	return [:len()-]
}