package sqlite3

import (
	
	
	
	
	

	

	
)

// CollationNeeded registers a callback to be invoked
// whenever an unknown collation sequence is required.
//
// https://sqlite.org/c3ref/collation_needed.html
func ( *Conn) ( func( *Conn,  string)) error {
	var  int32
	if  != nil {
		 = 1
	}
	 := res_t(.call("sqlite3_collation_needed_go", stk_t(.handle), stk_t()))
	if  := .error();  != nil {
		return 
	}
	.collation = 
	return nil
}

// AnyCollationNeeded uses [Conn.CollationNeeded] to register
// a fake collating function for any unknown collating sequence.
// The fake collating function works like BINARY.
//
// This can be used to load schemas that contain
// one or more unknown collating sequences.
func ( Conn) () error {
	 := res_t(.call("sqlite3_anycollseq_init", stk_t(.handle), 0, 0))
	if  := .error();  != nil {
		return 
	}
	.collation = nil
	return nil
}

// CreateCollation defines a new collating sequence.
//
// https://sqlite.org/c3ref/create_collation.html
func ( *Conn) ( string,  CollatingFunction) error {
	var  ptr_t
	defer .arena.mark()()
	 := .arena.string()
	if  != nil {
		 = util.AddHandle(.ctx, )
	}
	 := res_t(.call("sqlite3_create_collation_go",
		stk_t(.handle), stk_t(), stk_t()))
	return .error()
}

// CollatingFunction is the type of a collation callback.
// Implementations must not retain a or b.
type CollatingFunction func(a, b []byte) int

// CreateFunction defines a new scalar SQL function.
//
// https://sqlite.org/c3ref/create_function.html
func ( *Conn) ( string,  int,  FunctionFlag,  ScalarFunction) error {
	var  ptr_t
	defer .arena.mark()()
	 := .arena.string()
	if  != nil {
		 = util.AddHandle(.ctx, )
	}
	 := res_t(.call("sqlite3_create_function_go",
		stk_t(.handle), stk_t(), stk_t(),
		stk_t(), stk_t()))
	return .error()
}

// ScalarFunction is the type of a scalar SQL function.
// Implementations must not retain arg.
type ScalarFunction func(ctx Context, arg ...Value)

// CreateAggregateFunction defines a new aggregate SQL function.
//
// https://sqlite.org/c3ref/create_function.html
func ( *Conn) ( string,  int,  FunctionFlag,  AggregateSeqFunction) error {
	var  ptr_t
	defer .arena.mark()()
	 := .arena.string()
	if  != nil {
		 = util.AddHandle(.ctx, AggregateConstructor(func() AggregateFunction {
			var  aggregateFunc
			 := func( func(struct{}) bool) {
				 := func( func([]Value) bool) {
					for (.arg) {
						if !(struct{}{}) {
							break
						}
					}
				}
				(&.ctx, )
			}
			.next, .stop = iter.Pull()
			return &
		}))
	}
	 := res_t(.call("sqlite3_create_aggregate_function_go",
		stk_t(.handle), stk_t(), stk_t(),
		stk_t(), stk_t()))
	return .error()
}

// AggregateSeqFunction is the type of an aggregate SQL function.
// Implementations must not retain the slices yielded by seq.
type AggregateSeqFunction func(ctx *Context, seq iter.Seq[[]Value])

// CreateWindowFunction defines a new aggregate or aggregate window SQL function.
// If fn returns a [WindowFunction], an aggregate window function is created.
// If fn returns an [io.Closer], it will be called to free resources.
//
// https://sqlite.org/c3ref/create_function.html
func ( *Conn) ( string,  int,  FunctionFlag,  AggregateConstructor) error {
	var  ptr_t
	defer .arena.mark()()
	 := .arena.string()
	if  != nil {
		 = util.AddHandle(.ctx, AggregateConstructor(func() AggregateFunction {
			 := ()
			if ,  := .(WindowFunction);  {
				return 
			}
			return 
		}))
	}
	 := res_t(.call("sqlite3_create_window_function_go",
		stk_t(.handle), stk_t(), stk_t(),
		stk_t(), stk_t()))
	return .error()
}

// AggregateConstructor is a an [AggregateFunction] constructor.
type AggregateConstructor func() AggregateFunction

// AggregateFunction is the interface an aggregate function should implement.
//
// https://sqlite.org/appfunc.html
type AggregateFunction interface {
	// Step is invoked to add a row to the current window.
	// The function arguments, if any, corresponding to the row being added, are passed to Step.
	// Implementations must not retain arg.
	Step(ctx Context, arg ...Value)

	// Value is invoked to return the current (or final) value of the aggregate.
	Value(ctx Context)
}

// WindowFunction is the interface an aggregate window function should implement.
//
// https://sqlite.org/windowfunctions.html
type WindowFunction interface {
	AggregateFunction

	// Inverse is invoked to remove the oldest presently aggregated result of Step from the current window.
	// The function arguments, if any, are those passed to Step for the row being removed.
	// Implementations must not retain arg.
	Inverse(ctx Context, arg ...Value)
}

// OverloadFunction overloads a function for a virtual table.
//
// https://sqlite.org/c3ref/overload_function.html
func ( *Conn) ( string,  int) error {
	defer .arena.mark()()
	 := .arena.string()
	 := res_t(.call("sqlite3_overload_function",
		stk_t(.handle), stk_t(), stk_t()))
	return .error()
}

func destroyCallback( context.Context,  api.Module,  ptr_t) {
	util.DelHandle(, )
}

func collationCallback( context.Context,  api.Module, ,  ptr_t,  uint32,  ptr_t) {
	if ,  := .Value(connKey{}).(*Conn);  && .handle ==  && .collation != nil {
		 := util.ReadString(, , _MAX_NAME)
		.collation(, )
	}
}

func compareCallback( context.Context,  api.Module,  ptr_t,  int32,  ptr_t,  int32,  ptr_t) uint32 {
	 := util.GetHandle(, ).(CollatingFunction)
	return uint32((util.View(, , int64()), util.View(, , int64())))
}

func funcCallback( context.Context,  api.Module, ,  ptr_t,  int32,  ptr_t) {
	 := .Value(connKey{}).(*Conn)
	 := callbackArgs(, , )
	defer returnArgs()
	 := util.GetHandle(.ctx, ).(ScalarFunction)
	(Context{, }, *...)
}

func stepCallback( context.Context,  api.Module, , ,  ptr_t,  int32,  ptr_t) {
	 := .Value(connKey{}).(*Conn)
	 := callbackArgs(, , )
	defer returnArgs()
	,  := callbackAggregate(, , )
	.Step(Context{, }, *...)
}

func valueCallback( context.Context,  api.Module, , ,  ptr_t,  int32) {
	 := .Value(connKey{}).(*Conn)
	,  := callbackAggregate(, , )
	.Value(Context{, })

	// Cleanup.
	if  != 0 {
		var  error
		if  != 0 {
			 = util.DelHandle(, )
		} else if ,  := .(io.Closer);  {
			 = .Close()
		}
		if  != nil {
			Context{, }.ResultError()
			return // notest
		}
	}
}

func inverseCallback( context.Context,  api.Module, ,  ptr_t,  int32,  ptr_t) {
	 := .Value(connKey{}).(*Conn)
	 := callbackArgs(, , )
	defer returnArgs()
	 := util.GetHandle(.ctx, ).(WindowFunction)
	.Inverse(Context{, }, *...)
}

func callbackAggregate( *Conn, ,  ptr_t) (AggregateFunction, ptr_t) {
	if  == 0 {
		 := util.Read32[ptr_t](.mod, )
		return util.GetHandle(.ctx, ).(AggregateFunction), 
	}

	// We need to create the aggregate.
	 := util.GetHandle(.ctx, ).(AggregateConstructor)()
	if  != 0 {
		 := util.AddHandle(.ctx, )
		util.Write32(.mod, , )
		return , 
	}
	return , 0
}

var (
	valueArgsPool sync.Pool
	valueArgsLen  atomic.Int32
)

func callbackArgs( *Conn,  int32,  ptr_t) *[]Value {
	,  := valueArgsPool.Get().(*[]Value)
	if ! || cap(*) < int() {
		 := valueArgsLen.Or() | 
		 := make([]Value, )
		 = &
	}
	 := (*)[:]
	for  := range  {
		[] = Value{
			c:      ,
			handle: util.Read32[ptr_t](.mod, +ptr_t()*ptrlen),
		}
	}
	* = 
	return 
}

func returnArgs( *[]Value) {
	valueArgsPool.Put()
}

type aggregateFunc struct {
	next func() (struct{}, bool)
	stop func()
	ctx  Context
	arg  []Value
}

func ( *aggregateFunc) ( Context,  ...Value) {
	.ctx = 
	.arg = append(.arg[:0], ...)
	if ,  := .next(); ! {
		.stop()
	}
}

func ( *aggregateFunc) ( Context) {
	.ctx = 
	.stop()
}

func ( *aggregateFunc) () error {
	.stop()
	return nil
}