package dataext

import (
	"encoding/json"
	"errors"
	"gogs.mikescher.com/BlackForestBytes/goext/langext"
)

type JsonOpt[T any] struct {
	isSet bool
	value T
}

func NewJsonOpt[T any](v T) JsonOpt[T] {
	return JsonOpt[T]{isSet: true, value: v}
}

func EmptyJsonOpt[T any]() JsonOpt[T] {
	return JsonOpt[T]{isSet: false}
}

// MarshalJSON returns m as the JSON encoding of m.
func (m JsonOpt[T]) MarshalJSON() ([]byte, error) {
	if !m.isSet {
		return []byte("null"), nil // actually this would be undefined - but undefined is not valid JSON
	}

	return json.Marshal(m.value)
}

// UnmarshalJSON sets *m to a copy of data.
func (m *JsonOpt[T]) UnmarshalJSON(data []byte) error {
	if m == nil {
		return errors.New("JsonOpt: UnmarshalJSON on nil pointer")
	}

	m.isSet = true
	return json.Unmarshal(data, &m.value)
}

func (m JsonOpt[T]) IsSet() bool {
	return m.isSet
}

func (m JsonOpt[T]) IsUnset() bool {
	return !m.isSet
}

func (m JsonOpt[T]) Value() (T, bool) {
	if !m.isSet {
		return *new(T), false
	}
	return m.value, true
}

func (m JsonOpt[T]) ValueOrNil() *T {
	if !m.isSet {
		return nil
	}
	return &m.value
}

func (m JsonOpt[T]) ValueDblPtrOrNil() **T {
	if !m.isSet {
		return nil
	}
	return langext.DblPtr(m.value)
}

func (m JsonOpt[T]) MustValue() T {
	if !m.isSet {
		panic("value not set")
	}
	return m.value
}

func (m JsonOpt[T]) IfSet(fn func(v T)) bool {
	if !m.isSet {
		return false
	}
	fn(m.value)
	return true
}