package pointer

import (
	"encoding/json"
	"fmt"

	"github.com/jinzhu/copier"
)

func Pointer[T any](v T) *T {
	return &v
}

func Deref[T any](v *T, def T) T {
	if v == nil {
		return def
	}
	return *v
}

func DerefAny[T any](v any, def T) T {
	t, ok := v.(T)
	if !ok {
		return def
	}
	return t
}

// OrDefault returns def when v is the zero value of T.
func OrDefault[T comparable](v T, def T) T {
	var zero T
	if v == zero {
		return def
	}
	return v
}

func DeepCopy[T any](v *T) (*T, error) {
	if v == nil {
		return nil, fmt.Errorf("nil pointer")
	}

	var n T
	err := copier.CopyWithOption(&n, v, copier.Option{DeepCopy: true})
	if err != nil {
		return nil, err
	}
	return &n, nil
}

func StructToMap(v any) (map[string]any, error) {
	b, err := json.Marshal(v)
	if err != nil {
		return nil, err
	}

	var m map[string]any
	if err := json.Unmarshal(b, &m); err != nil {
		return nil, err
	}
	return m, nil
}

func MapToStruct(m map[string]any, v any) error {
	b, err := json.Marshal(m)
	if err != nil {
		return err
	}

	if err := json.Unmarshal(b, v); err != nil {
		return err
	}
	return nil
}

func MarshalWithoutError[T any](v T) []byte {
	data, err := json.Marshal(v)
	if err != nil {
		return []byte(err.Error())
	}

	return data
}
