package bun

import (
	
	
	
	
	
	

	
)

var errNilModel = errors.New("bun: Model(nil)")

var timeType = reflect.TypeOf((*time.Time)(nil)).Elem()

type Model interface {
	ScanRows(ctx context.Context, rows *sql.Rows) (int, error)
	Value() interface{}
}

type rowScanner interface {
	ScanRow(ctx context.Context, rows *sql.Rows) error
}

type model interface {
	Model
}

type tableModel interface {
	model

	schema.BeforeScanHook
	schema.AfterScanHook
	ScanColumn(column string, src interface{}) error

	Table() *schema.Table
	Relation() *schema.Relation

	Join(string) *relationJoin
	GetJoin(string) *relationJoin
	GetJoins() []relationJoin
	AddJoin(relationJoin) *relationJoin

	Root() reflect.Value
	ParentIndex() []int
	Mount(reflect.Value)

	updateSoftDeleteField(time.Time) error
}

func ( *DB,  []interface{}) (model, error) {
	if len() == 1 {
		return _newModel(, [0], true)
	}

	 := make([]reflect.Value, len())

	for ,  := range  {
		 := reflect.ValueOf()
		if .Kind() != reflect.Ptr {
			return nil, fmt.Errorf("bun: Scan(non-pointer %T)", )
		}

		 = .Elem()
		if .Kind() != reflect.Slice {
			return newScanModel(, ), nil
		}

		[] = 
	}

	return newSliceModel(, , ), nil
}

func ( *DB,  interface{}) (model, error) {
	return _newModel(, , false)
}

func ( *DB,  interface{},  bool) (model, error) {
	switch dest := .(type) {
	case nil:
		return nil, errNilModel
	case Model:
		return , nil
	case sql.Scanner:
		if ! {
			return nil, fmt.Errorf("bun: Model(unsupported %T)", )
		}
		return newScanModel(, []interface{}{}), nil
	}

	 := reflect.ValueOf()
	if !.IsValid() {
		return nil, errNilModel
	}
	if .Kind() != reflect.Ptr {
		return nil, fmt.Errorf("bun: Model(non-pointer %T)", )
	}

	if .IsNil() {
		 := .Type().Elem()
		if .Kind() == reflect.Struct {
			return newStructTableModel(, , .Table()), nil
		}
		return nil, fmt.Errorf("bun: Model(nil %T)", )
	}

	 = .Elem()

	switch .Kind() {
	case reflect.Map:
		 := .Type()
		if  := validMap();  != nil {
			return nil, 
		}
		 := .Addr().Interface().(*map[string]interface{})
		return newMapModel(, ), nil
	case reflect.Struct:
		if .Type() != timeType {
			return newStructTableModelValue(, , ), nil
		}
	case reflect.Slice:
		switch  := sliceElemType(); .Kind() {
		case reflect.Struct:
			if  != timeType {
				return newSliceTableModel(, , , ), nil
			}
		case reflect.Map:
			if  := validMap();  != nil {
				return nil, 
			}
			 := .Addr().Interface().(*[]map[string]interface{})
			return newMapSliceModel(, ), nil
		}
		return newSliceModel(, []interface{}{}, []reflect.Value{}), nil
	}

	if  {
		return newScanModel(, []interface{}{}), nil
	}

	return nil, fmt.Errorf("bun: Model(unsupported %T)", )
}

func (
	 *DB,
	 *schema.Table,
	 reflect.Value,
	 []int,
	 *schema.Relation,
) (tableModel, error) {
	 := typeByIndex(.Type, )

	if .Kind() == reflect.Struct {
		return &structTableModel{
			db:    ,
			table: .Dialect().Tables().Get(),
			rel:   ,

			root:  ,
			index: ,
		}, nil
	}

	if .Kind() == reflect.Slice {
		 := indirectType(.Elem())
		if .Kind() == reflect.Struct {
			 := sliceTableModel{
				structTableModel: structTableModel{
					db:    ,
					table: .Dialect().Tables().Get(),
					rel:   ,

					root:  ,
					index: ,
				},
			}
			.init()
			return &, nil
		}
	}

	return nil, fmt.Errorf("bun: NewModel(%s)", )
}

func ( reflect.Type) error {
	if .Key().Kind() != reflect.String || .Elem().Kind() != reflect.Interface {
		return fmt.Errorf("bun: Model(unsupported %s) (expected *map[string]interface{})",
			)
	}
	return nil
}

//------------------------------------------------------------------------------

func ( model) bool {
	switch .(type) {
	case *mapModel,
		*structTableModel,
		*scanModel:
		return true
	default:
		return false
	}
}