package datatypes

import (
	
	
	
	
	
	
	
)

// NullString represents a string that may be null.
// NullString implements the [Scanner] interface so
// it can be used as a scan destination:
//
//	var s NullString
//	err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)
//	...
//	if s.Valid {
//	   // use s.String
//	} else {
//	   // NULL value
//	}
type NullString = Null[string]

// NullInt64 represents an int64 that may be null.
// NullInt64 implements the [Scanner] interface so
// it can be used as a scan destination, similar to [NullString].
type NullInt64 = Null[int64]

// NullInt32 represents an int32 that may be null.
// NullInt32 implements the [Scanner] interface so
// it can be used as a scan destination, similar to [NullString].
type NullInt32 = Null[int32]

// NullInt16 represents an int16 that may be null.
// NullInt16 implements the [Scanner] interface so
// it can be used as a scan destination, similar to [NullString].
type NullInt16 = Null[int16]

// NullByte represents a byte that may be null.
// NullByte implements the [Scanner] interface so
// it can be used as a scan destination, similar to [NullString].
type NullByte = Null[byte]

// NullFloat64 represents a float64 that may be null.
// NullFloat64 implements the [Scanner] interface so
// it can be used as a scan destination, similar to [NullString].
type NullFloat64 = Null[float64]

// NullBool represents a bool that may be null.
// NullBool implements the [Scanner] interface so
// it can be used as a scan destination, similar to [NullString].
type NullBool = Null[bool]

// NullTime represents a [time.Time] that may be null.
// NullTime implements the [Scanner] interface so
// it can be used as a scan destination, similar to [NullString].
type NullTime = Null[time.Time]

// Null represents a value that may be null.
// Null implements the [Scanner] interface so
// it can be used as a scan destination:
//
//	var s Null[string]
//	err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)
//	...
//	if s.Valid {
//	   // use s.V
//	} else {
//	   // NULL value
//	}
type Null[ any] struct {
	V     
	Valid bool
}

func ( *Null[]) ( any) error {
	if  == nil {
		.V, .Valid = *new(), false
		return nil
	}
	.Valid = true
	return convertAssign(&.V, )
}

func ( Null[]) () (driver.Value, error) {
	if !.Valid {
		return nil, nil
	}
	return .V, nil
}

// NewNull returns a new, non-null Null.
func [ any]( ) Null[] {
	return Null[]{V: , Valid: true}
}

var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error

// convertAssign is the same as convertAssignRows, but without the optional
// rows argument.
func convertAssign(,  any) error {
	return convertAssignRows(, , nil)
}

// convertAssignRows copies to dest the value in src, converting it if possible.
// An error is returned if the copy would result in loss of information.
// dest should be a pointer type. If rows is passed in, the rows will
// be used as the parent for any cursor values converted from a
// driver.Rows to a *Rows.
func convertAssignRows(,  any,  *sql.Rows) error {
	// Common cases, without reflect.
	switch s := .(type) {
	case string:
		switch d := .(type) {
		case *string:
			if  == nil {
				return errNilPtr
			}
			* = 
			return nil
		case *[]byte:
			if  == nil {
				return errNilPtr
			}
			* = []byte()
			return nil
		case *sql.RawBytes:
			if  == nil {
				return errNilPtr
			}
			* = append((*)[:0], ...)
			return nil
		}
	case []byte:
		switch d := .(type) {
		case *string:
			if  == nil {
				return errNilPtr
			}
			* = string()
			return nil
		case *any:
			if  == nil {
				return errNilPtr
			}
			* = cloneBytes()
			return nil
		case *[]byte:
			if  == nil {
				return errNilPtr
			}
			* = cloneBytes()
			return nil
		case *sql.RawBytes:
			if  == nil {
				return errNilPtr
			}
			* = 
			return nil
		}
	case time.Time:
		switch d := .(type) {
		case *time.Time:
			* = 
			return nil
		case *string:
			* = .Format(time.RFC3339Nano)
			return nil
		case *[]byte:
			if  == nil {
				return errNilPtr
			}
			* = []byte(.Format(time.RFC3339Nano))
			return nil
		case *sql.RawBytes:
			if  == nil {
				return errNilPtr
			}
			* = .AppendFormat((*)[:0], time.RFC3339Nano)
			return nil
		}
	case decimalDecompose:
		switch d := .(type) {
		case decimalCompose:
			return .Compose(.Decompose(nil))
		}
	case nil:
		switch d := .(type) {
		case *any:
			if  == nil {
				return errNilPtr
			}
			* = nil
			return nil
		case *[]byte:
			if  == nil {
				return errNilPtr
			}
			* = nil
			return nil
		case *sql.RawBytes:
			if  == nil {
				return errNilPtr
			}
			* = nil
			return nil
		}
	}

	var  reflect.Value

	switch d := .(type) {
	case *string:
		 = reflect.ValueOf()
		switch .Kind() {
		case reflect.Bool,
			reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
			reflect.Float32, reflect.Float64:
			* = asString()
			return nil
		}
	case *[]byte:
		 = reflect.ValueOf()
		if ,  := asBytes(nil, );  {
			* = 
			return nil
		}
	case *sql.RawBytes:
		 = reflect.ValueOf()
		if ,  := asBytes([]byte(*)[:0], );  {
			* = sql.RawBytes()
			return nil
		}
	case *bool:
		,  := driver.Bool.ConvertValue()
		if  == nil {
			* = .(bool)
		}
		return 
	case *any:
		* = 
		return nil
	}

	if ,  := .(sql.Scanner);  {
		return .Scan()
	}

	 := reflect.ValueOf()
	if .Kind() != reflect.Pointer {
		return errors.New("destination not a pointer")
	}
	if .IsNil() {
		return errNilPtr
	}

	if !.IsValid() {
		 = reflect.ValueOf()
	}

	 := reflect.Indirect()
	if .IsValid() && .Type().AssignableTo(.Type()) {
		switch b := .(type) {
		case []byte:
			.Set(reflect.ValueOf(cloneBytes()))
		default:
			.Set()
		}
		return nil
	}

	if .Kind() == .Kind() && .Type().ConvertibleTo(.Type()) {
		.Set(.Convert(.Type()))
		return nil
	}

	// The following conversions use a string value as an intermediate representation
	// to convert between various numeric types.
	//
	// This also allows scanning into user defined types such as "type Int int64".
	// For symmetry, also check for string destination types.
	switch .Kind() {
	case reflect.Pointer:
		if  == nil {
			.Set(reflect.Zero(.Type()))
			return nil
		}
		.Set(reflect.New(.Type().Elem()))
		return (.Interface(), , )
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if  == nil {
			return fmt.Errorf("converting NULL to %s is unsupported", .Kind())
		}
		 := asString()
		,  := strconv.ParseInt(, 10, .Type().Bits())
		if  != nil {
			 = strconvErr()
			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", , , .Kind(), )
		}
		.SetInt()
		return nil
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		if  == nil {
			return fmt.Errorf("converting NULL to %s is unsupported", .Kind())
		}
		 := asString()
		,  := strconv.ParseUint(, 10, .Type().Bits())
		if  != nil {
			 = strconvErr()
			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", , , .Kind(), )
		}
		.SetUint()
		return nil
	case reflect.Float32, reflect.Float64:
		if  == nil {
			return fmt.Errorf("converting NULL to %s is unsupported", .Kind())
		}
		 := asString()
		,  := strconv.ParseFloat(, .Type().Bits())
		if  != nil {
			 = strconvErr()
			return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", , , .Kind(), )
		}
		.SetFloat()
		return nil
	case reflect.String:
		if  == nil {
			return fmt.Errorf("converting NULL to %s is unsupported", .Kind())
		}
		switch v := .(type) {
		case string:
			.SetString()
			return nil
		case []byte:
			.SetString(string())
			return nil
		}
	}

	return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", , )
}

func strconvErr( error) error {
	if ,  := .(*strconv.NumError);  {
		return .Err
	}
	return 
}

func asString( any) string {
	switch v := .(type) {
	case string:
		return 
	case []byte:
		return string()
	}
	 := reflect.ValueOf()
	switch .Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(.Int(), 10)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(.Uint(), 10)
	case reflect.Float64:
		return strconv.FormatFloat(.Float(), 'g', -1, 64)
	case reflect.Float32:
		return strconv.FormatFloat(.Float(), 'g', -1, 32)
	case reflect.Bool:
		return strconv.FormatBool(.Bool())
	}
	return fmt.Sprintf("%v", )
}

func asBytes( []byte,  reflect.Value) ( []byte,  bool) {
	switch .Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.AppendInt(, .Int(), 10), true
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.AppendUint(, .Uint(), 10), true
	case reflect.Float32:
		return strconv.AppendFloat(, .Float(), 'g', -1, 32), true
	case reflect.Float64:
		return strconv.AppendFloat(, .Float(), 'g', -1, 64), true
	case reflect.Bool:
		return strconv.AppendBool(, .Bool()), true
	case reflect.String:
		 := .String()
		return append(, ...), true
	}
	return
}

type decimalDecompose interface {
	// Decompose returns the internal decimal state in parts.
	// If the provided buf has sufficient capacity, buf may be returned as the coefficient with
	// the value set and length set as appropriate.
	Decompose(buf []byte) (form byte, negative bool, coefficient []byte, exponent int32)
}

type decimalCompose interface {
	// Compose sets the internal decimal value from parts. If the value cannot be
	// represented then an error should be returned.
	Compose(form byte, negative bool, coefficient []byte, exponent int32) error
}

// cloneBytes returns a copy of b[:len(b)].
// The result may have additional unused capacity.
// cloneBytes(nil) returns nil.
func cloneBytes( []byte) []byte {
	if  == nil {
		return nil
	}
	return append([]byte{}, ...)
}