// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.

package optionalnullable

import (
	"bytes"
	"encoding/json"
	"reflect"
)

// OptionalNullable represents a field that can distinguish between three states:
// 1. Set to a value: field is present with a non-nil value
// 2. Set to nil: field is present but explicitly set to null in JSON
// 3. Unset: field is omitted from JSON entirely
//
// This type is designed to work with JSON marshaling/unmarshaling and supports
// the `omitempty` struct tag to properly omit unset fields from JSON output.
//
// Usage:
//
//	type User struct {
//	    Name  OptionalNullable[string] `json:"name,omitempty"`
//	    Age   OptionalNullable[int]    `json:"age,omitempty"`
//	    Tags  OptionalNullable[[]string] `json:"tags,omitempty"`
//	}
//
//	// Set to value
//	name := "John"
//	user.Name = From(&name)
//
//	// Set to nil (will appear as "name": null in JSON)
//	user.Name = From[string](nil)
//
//	// Leave unset (will be omitted from JSON with omitempty)
//	user := User{}
//
// WARNING: Do NOT use *OptionalNullable[T] as a field type. Always use OptionalNullable[T] directly.
// Using *OptionalNullable[T] will break the omitempty behavior and JSON marshaling.
//
// The type is implemented as a map[bool]*T where:
// - nil map represents unset state
// - Map with true key represents set state (value may be nil)
type OptionalNullable[T any] map[bool]*T

// From creates a new OptionalNullable with the given value.
// Pass nil to create a OptionalNullable that is set to null.
// Pass a pointer to a value to create a OptionalNullable with that value.
//
// Examples:
//
//	hello := "hello"
//	From(&hello)  // set to "hello"
//	From[string](nil)       // set to null
func From[T any](value *T) OptionalNullable[T] {
	return map[bool]*T{
		true: value,
	}
}

// IsNull returns true if the OptionalNullable is explicitly set to nil.
// Returns false if the OptionalNullable is unset or has a value.
//
// Note: This differs from traditional null checks because unset fields
// return false, not true. Use IsSet() to check if a field was provided.
func (n OptionalNullable[T]) IsNull() bool {
	v, ok := n[true]
	return ok && v == nil
}

// IsSet returns true if the OptionalNullable has been explicitly set (to either a value or nil).
// Returns false if the OptionalNullable is unset (omitted from JSON).
//
// This is the key method for distinguishing between:
// - Set to nil: IsSet() = true, IsNull() = true
// - Unset: IsSet() = false, IsNull() = false
func (n OptionalNullable[T]) IsSet() bool {
	_, ok := n[true]
	return ok
}

// Get returns the internal pointer and whether the field was set.
//
// Return values:
// - (ptr, true): field was set (ptr may be nil if set to null)
// - (nil, false): field was unset/omitted
//
// This method provides direct access to the internal pointer representation.
func (n OptionalNullable[T]) Get() (*T, bool) {
	v, ok := n[true]
	return v, ok
}

// GetOrZero returns the value and whether it was set.
//
// Return values:
// - (value, true): field was set to a non-nil value
// - (zero, true): field was explicitly set to nil
// - (zero, false): field was unset/omitted
//
// Examples:
//
//	val, ok := nullable.GetOrZero()
//	if !ok {
//	    // Field was unset/omitted
//	} else if nullable.IsNull() {
//	    // Field was explicitly set to null
//	} else {
//	    // Field has a value: val
//	}
func (n OptionalNullable[T]) GetOrZero() (T, bool) {
	var zero T

	if v, ok := n[true]; ok {
		if v == nil {
			return zero, true
		}
		return *v, true
	}
	return zero, false
}

// GetUntyped returns the value as interface{} and whether it was set.
// This is useful for reflection-based code that needs to work with the value
// without knowing the specific type T.
//
// Return values:
// - (value, true): field was set to a non-nil value
// - (nil, true): field was explicitly set to nil
// - (nil, false): field was unset/omitted
func (n OptionalNullable[T]) GetUntyped() (interface{}, bool) {
	if v, ok := n[true]; ok {
		if v == nil {
			return nil, true
		}
		return *v, true
	}
	return nil, false
}

// Set sets the OptionalNullable to the given value pointer.
// Pass nil to set the field to null.
// Pass a pointer to a value to set the field to that value.
//
// Examples:
//
//	nullable.Set(ptrFrom("hello"))  // set to "hello"
//	nullable.Set(nil)               // set to null
func (n *OptionalNullable[T]) Set(value *T) {
	*n = map[bool]*T{
		true: value,
	}
}

// Unset removes the value, making the field unset/omitted.
// After calling Unset(), IsSet() will return false and the field
// will be omitted from JSON output when using omitempty.
func (n *OptionalNullable[T]) Unset() {
	*n = map[bool]*T{}
}

// MarshalJSON implements json.Marshaler.
//
// Behavior:
// - Unset fields: omitted from JSON when struct field has omitempty tag
// - Null fields: serialized as "null"
// - Value fields: serialized as the actual value
//
// The omitempty behavior works because an empty map is considered
// a zero value by Go's JSON package.
func (n OptionalNullable[T]) MarshalJSON() ([]byte, error) {
	if n.IsNull() {
		return []byte("null"), nil
	}

	return json.Marshal(n[true])
}

// UnmarshalJSON implements json.Unmarshaler.
//
// Behavior:
// - "null" in JSON: sets the field to null (IsSet=true, IsNull=true)
// - Any other value: sets the field to that value (IsSet=true, IsNull=false)
// - Missing from JSON: field remains unset (IsSet=false, IsNull=false)
func (n *OptionalNullable[T]) UnmarshalJSON(data []byte) error {
	if bytes.Equal(data, []byte("null")) {
		n.Set(nil)
		return nil
	}
	var v T
	if err := json.Unmarshal(data, &v); err != nil {
		return err
	}
	n.Set(&v)
	return nil
}

// NullableInterface defines the interface that all OptionalNullable[T] types implement.
// This interface provides untyped access to optional nullable values for reflection-based code.
type OptionalNullableInterface interface {
	GetUntyped() (interface{}, bool)
}

// AsOptionalNullable attempts to convert a reflect.Value to a OptionalNullableInterface.
// This is a helper function for reflection-based code that needs to check
// if a value implements the optional nullable interface pattern.
//
// Returns:
// - (nullable, true): if the value implements OptionalNullableInterface
// - (nil, false): if the value does not implement OptionalNullableInterface
//
// Example usage:
//
//	if nullable, ok := AsOptionalNullable(reflectValue); ok {
//	    if value, isSet := nullable.GetUntyped(); isSet {
//	        // Handle the nullable value
//	    }
//	}
func AsOptionalNullable(v reflect.Value) (OptionalNullableInterface, bool) {
	// Check if the value can be converted to an interface first
	if !v.CanInterface() {
		return nil, false
	}

	// Check if the underlying value is a nil map (unset nullable)
	if v.Kind() == reflect.Map && v.IsNil() {
		return nil, false
	}

	if nullable, ok := v.Interface().(OptionalNullableInterface); ok {
		return nullable, true
	}
	return nil, false
}
