package coredb

import "context"

type Row interface {
	Scan(...any) error
}

type Rows interface {
	Close()
	Err() error
	Next() bool
	Scan(...any) error
}

type Result interface {
	RowsAffected() int64
}

type TxIsolationLevel string

const (
	ReadUncommitted TxIsolationLevel = "read uncommitted"
	ReadCommitted   TxIsolationLevel = "read committed"
	RepeatableRead  TxIsolationLevel = "repeatable read"
	Serializable    TxIsolationLevel = "serializable"
)

type TxAccessMode string

const (
	ReadWrite TxAccessMode = "read write"
	ReadOnly  TxAccessMode = "read only"
)

type TxOptions struct {
	IsoLevel   TxIsolationLevel
	AccessMode TxAccessMode
}

type QueryRower interface {
	QueryRow(context.Context, string, ...any) Row
}

type Queryer interface {
	QueryRower
	Query(context.Context, string, ...any) (Rows, error)
}

type QueryExecer interface {
	Queryer
	Exec(context.Context, string, ...any) (Result, error)
}

type Tx interface {
	QueryExecer
	Commit(context.Context) error
	Rollback(context.Context) error
}

type TxBeginner interface {
	BeginTx(context.Context, TxOptions) (Tx, error)
}

type DB interface {
	QueryExecer
	TxBeginner
}

// Getter is implemented by adapters that can scan one row into a struct or scalar.
type Getter interface {
	Get(context.Context, any, string, ...any) error
}

// Selector is implemented by adapters that can scan rows into a slice of structs or scalars.
type Selector interface {
	Select(context.Context, any, string, ...any) error
}

// NamedExecer is implemented by adapters that can execute named-parameter statements.
type NamedExecer interface {
	NamedExec(context.Context, string, any) (Result, error)
}

type rowsAffectedResult struct {
	rowsAffected int64
}

func (result rowsAffectedResult) RowsAffected() int64 {
	return result.rowsAffected
}
