// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.

// number.go
package types

import (
	"fmt"

	"git.portale-stac.it/go-pkg/expr/kern"
	"git.portale-stac.it/go-pkg/expr/types/float"
	"git.portale-stac.it/go-pkg/expr/types/fract"
	"git.portale-stac.it/go-pkg/expr/types/str"
)

func IsInteger(v any) (ok bool) {
	_, ok = v.(int64)
	return ok
}

func IsNumber(v any) (ok bool) {
	return float.IsFloat(v) || IsInteger(v)
}

func IsNumOrFract(v any) (ok bool) {
	return float.IsFloat(v) || IsInteger(v) || fract.IsFraction(v)
}

func IsNumberString(v any) (ok bool) {
	return str.IsString(v) || IsNumber(v)
}

func NumAsFloat(v any) (f float64) {
	var ok bool
	if f, ok = v.(float64); !ok {
		if fract, ok := v.(*fract.FractionType); ok {
			f = fract.ToFloat()
		} else {
			i, _ := v.(int64)
			f = float64(i)
		}
	}
	return
}

func AnyInteger(v any) (i int64, ok bool) {
	ok = true
	switch intval := v.(type) {
	case int:
		i = int64(intval)
	case uint8:
		i = int64(intval)
	case uint16:
		i = int64(intval)
	case uint64:
		i = int64(intval)
	case uint32:
		i = int64(intval)
	case int8:
		i = int64(intval)
	case int16:
		i = int64(intval)
	case int32:
		i = int64(intval)
	case int64:
		i = intval
	default:
		ok = false
	}
	return
}

func ToGoInt(value any, description string) (i int, err error) {
	if valueInt64, ok := value.(int64); ok {
		i = int(valueInt64)
	} else if valueInt, ok := value.(int); ok {
		i = valueInt
	} else {
		err = fmt.Errorf("%s expected integer, got %s (%v)", description, kern.TypeName(value), value)
	}
	return
}

func ToGoInt64(value any, description string) (i int64, err error) {
	if valueInt64, ok := value.(int64); ok {
		i = valueInt64
	} else if valueInt, ok := value.(int); ok {
		i = int64(valueInt)
	} else {
		err = fmt.Errorf("%s expected integer, got %s (%v)", description, kern.TypeName(value), value)
	}
	return
}
