package assert

import (
	
	
	
	
)

// Deprecated: CompareType has only ever been for internal use and has accidentally been published since v1.6.0. Do not use it.
type CompareType = compareResult

type compareResult int

const (
	compareLess compareResult = iota - 1
	compareEqual
	compareGreater
)

var (
	intType   = reflect.TypeOf(int(1))
	int8Type  = reflect.TypeOf(int8(1))
	int16Type = reflect.TypeOf(int16(1))
	int32Type = reflect.TypeOf(int32(1))
	int64Type = reflect.TypeOf(int64(1))

	uintType   = reflect.TypeOf(uint(1))
	uint8Type  = reflect.TypeOf(uint8(1))
	uint16Type = reflect.TypeOf(uint16(1))
	uint32Type = reflect.TypeOf(uint32(1))
	uint64Type = reflect.TypeOf(uint64(1))

	uintptrType = reflect.TypeOf(uintptr(1))

	float32Type = reflect.TypeOf(float32(1))
	float64Type = reflect.TypeOf(float64(1))

	stringType = reflect.TypeOf("")

	timeType  = reflect.TypeOf(time.Time{})
	bytesType = reflect.TypeOf([]byte{})
)

func compare(,  interface{},  reflect.Kind) (compareResult, bool) {
	 := reflect.ValueOf()
	 := reflect.ValueOf()

	// throughout this switch we try and avoid calling .Convert() if possible,
	// as this has a pretty big performance impact
	switch  {
	case reflect.Int:
		{
			,  := .(int)
			if ! {
				 = .Convert(intType).Interface().(int)
			}
			,  := .(int)
			if ! {
				 = .Convert(intType).Interface().(int)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Int8:
		{
			,  := .(int8)
			if ! {
				 = .Convert(int8Type).Interface().(int8)
			}
			,  := .(int8)
			if ! {
				 = .Convert(int8Type).Interface().(int8)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Int16:
		{
			,  := .(int16)
			if ! {
				 = .Convert(int16Type).Interface().(int16)
			}
			,  := .(int16)
			if ! {
				 = .Convert(int16Type).Interface().(int16)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Int32:
		{
			,  := .(int32)
			if ! {
				 = .Convert(int32Type).Interface().(int32)
			}
			,  := .(int32)
			if ! {
				 = .Convert(int32Type).Interface().(int32)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Int64:
		{
			,  := .(int64)
			if ! {
				 = .Convert(int64Type).Interface().(int64)
			}
			,  := .(int64)
			if ! {
				 = .Convert(int64Type).Interface().(int64)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Uint:
		{
			,  := .(uint)
			if ! {
				 = .Convert(uintType).Interface().(uint)
			}
			,  := .(uint)
			if ! {
				 = .Convert(uintType).Interface().(uint)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Uint8:
		{
			,  := .(uint8)
			if ! {
				 = .Convert(uint8Type).Interface().(uint8)
			}
			,  := .(uint8)
			if ! {
				 = .Convert(uint8Type).Interface().(uint8)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Uint16:
		{
			,  := .(uint16)
			if ! {
				 = .Convert(uint16Type).Interface().(uint16)
			}
			,  := .(uint16)
			if ! {
				 = .Convert(uint16Type).Interface().(uint16)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Uint32:
		{
			,  := .(uint32)
			if ! {
				 = .Convert(uint32Type).Interface().(uint32)
			}
			,  := .(uint32)
			if ! {
				 = .Convert(uint32Type).Interface().(uint32)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Uint64:
		{
			,  := .(uint64)
			if ! {
				 = .Convert(uint64Type).Interface().(uint64)
			}
			,  := .(uint64)
			if ! {
				 = .Convert(uint64Type).Interface().(uint64)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Float32:
		{
			,  := .(float32)
			if ! {
				 = .Convert(float32Type).Interface().(float32)
			}
			,  := .(float32)
			if ! {
				 = .Convert(float32Type).Interface().(float32)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.Float64:
		{
			,  := .(float64)
			if ! {
				 = .Convert(float64Type).Interface().(float64)
			}
			,  := .(float64)
			if ! {
				 = .Convert(float64Type).Interface().(float64)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	case reflect.String:
		{
			,  := .(string)
			if ! {
				 = .Convert(stringType).Interface().(string)
			}
			,  := .(string)
			if ! {
				 = .Convert(stringType).Interface().(string)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	// Check for known struct types we can check for compare results.
	case reflect.Struct:
		{
			// All structs enter here. We're not interested in most types.
			if !.CanConvert(timeType) {
				break
			}

			// time.Time can be compared!
			,  := .(time.Time)
			if ! {
				 = .Convert(timeType).Interface().(time.Time)
			}

			,  := .(time.Time)
			if ! {
				 = .Convert(timeType).Interface().(time.Time)
			}

			if .Before() {
				return compareLess, true
			}
			if .Equal() {
				return compareEqual, true
			}
			return compareGreater, true
		}
	case reflect.Slice:
		{
			// We only care about the []byte type.
			if !.CanConvert(bytesType) {
				break
			}

			// []byte can be compared!
			,  := .([]byte)
			if ! {
				 = .Convert(bytesType).Interface().([]byte)

			}
			,  := .([]byte)
			if ! {
				 = .Convert(bytesType).Interface().([]byte)
			}

			return compareResult(bytes.Compare(, )), true
		}
	case reflect.Uintptr:
		{
			,  := .(uintptr)
			if ! {
				 = .Convert(uintptrType).Interface().(uintptr)
			}
			,  := .(uintptr)
			if ! {
				 = .Convert(uintptrType).Interface().(uintptr)
			}
			if  >  {
				return compareGreater, true
			}
			if  ==  {
				return compareEqual, true
			}
			if  <  {
				return compareLess, true
			}
		}
	}

	return compareEqual, false
}

// Greater asserts that the first element is greater than the second
//
//	assert.Greater(t, 2, 1)
//	assert.Greater(t, float64(2), float64(1))
//	assert.Greater(t, "b", "a")
func ( TestingT,  interface{},  interface{},  ...interface{}) bool {
	if ,  := .(tHelper);  {
		.Helper()
	}
	 := fmt.Sprintf("\"%v\" is not greater than \"%v\"", , )
	return compareTwoValues(, , , []compareResult{compareGreater}, , ...)
}

// GreaterOrEqual asserts that the first element is greater than or equal to the second
//
//	assert.GreaterOrEqual(t, 2, 1)
//	assert.GreaterOrEqual(t, 2, 2)
//	assert.GreaterOrEqual(t, "b", "a")
//	assert.GreaterOrEqual(t, "b", "b")
func ( TestingT,  interface{},  interface{},  ...interface{}) bool {
	if ,  := .(tHelper);  {
		.Helper()
	}
	 := fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", , )
	return compareTwoValues(, , , []compareResult{compareGreater, compareEqual}, , ...)
}

// Less asserts that the first element is less than the second
//
//	assert.Less(t, 1, 2)
//	assert.Less(t, float64(1), float64(2))
//	assert.Less(t, "a", "b")
func ( TestingT,  interface{},  interface{},  ...interface{}) bool {
	if ,  := .(tHelper);  {
		.Helper()
	}
	 := fmt.Sprintf("\"%v\" is not less than \"%v\"", , )
	return compareTwoValues(, , , []compareResult{compareLess}, , ...)
}

// LessOrEqual asserts that the first element is less than or equal to the second
//
//	assert.LessOrEqual(t, 1, 2)
//	assert.LessOrEqual(t, 2, 2)
//	assert.LessOrEqual(t, "a", "b")
//	assert.LessOrEqual(t, "b", "b")
func ( TestingT,  interface{},  interface{},  ...interface{}) bool {
	if ,  := .(tHelper);  {
		.Helper()
	}
	 := fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", , )
	return compareTwoValues(, , , []compareResult{compareLess, compareEqual}, , ...)
}

// Positive asserts that the specified element is positive
//
//	assert.Positive(t, 1)
//	assert.Positive(t, 1.23)
func ( TestingT,  interface{},  ...interface{}) bool {
	if ,  := .(tHelper);  {
		.Helper()
	}
	 := reflect.Zero(reflect.TypeOf())
	 := fmt.Sprintf("\"%v\" is not positive", )
	return compareTwoValues(, , .Interface(), []compareResult{compareGreater}, , ...)
}

// Negative asserts that the specified element is negative
//
//	assert.Negative(t, -1)
//	assert.Negative(t, -1.23)
func ( TestingT,  interface{},  ...interface{}) bool {
	if ,  := .(tHelper);  {
		.Helper()
	}
	 := reflect.Zero(reflect.TypeOf())
	 := fmt.Sprintf("\"%v\" is not negative", )
	return compareTwoValues(, , .Interface(), []compareResult{compareLess}, , ...)
}

func compareTwoValues( TestingT,  interface{},  interface{},  []compareResult,  string,  ...interface{}) bool {
	if ,  := .(tHelper);  {
		.Helper()
	}

	 := reflect.ValueOf().Kind()
	 := reflect.ValueOf().Kind()
	if  !=  {
		return Fail(, "Elements should be the same type", ...)
	}

	,  := compare(, , )
	if ! {
		return Fail(, fmt.Sprintf(`Can not compare type "%T"`, ), ...)
	}

	if !containsValue(, ) {
		return Fail(, , ...)
	}

	return true
}

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

	return false
}