package jsonutil

import (
	"database/sql/driver"
	"encoding/json"
	"fmt"
)

// NullableRawMessage stores a JSON value that may be SQL NULL. Unlike a plain
// json.RawMessage, it implements sql.Scanner and can therefore read nullable
// JSON columns without failing. A nil value is encoded as JSON null.
type NullableRawMessage json.RawMessage

func (m *NullableRawMessage) Scan(value any) error {
	if value == nil {
		*m = nil
		return nil
	}

	switch value := value.(type) {
	case []byte:
		*m = append((*m)[:0], value...)
	case string:
		*m = append((*m)[:0], value...)
	default:
		return fmt.Errorf("NullableRawMessage.Scan: unsupported type %T", value)
	}
	return nil
}

func (m NullableRawMessage) Value() (driver.Value, error) {
	if m == nil {
		return nil, nil
	}
	return []byte(m), nil
}

func (m NullableRawMessage) MarshalJSON() ([]byte, error) {
	if m == nil {
		return []byte("null"), nil
	}
	if !json.Valid(m) {
		return nil, fmt.Errorf("invalid JSON")
	}
	return m, nil
}

func (m NullableRawMessage) Raw() json.RawMessage {
	return json.RawMessage(m)
}
