package callbacks

import (
	
	
	

	
	
	
	
)

// BeforeCreate before create hooks
func ( *gorm.DB) {
	if .Error == nil && .Statement.Schema != nil && !.Statement.SkipHooks && (.Statement.Schema.BeforeSave || .Statement.Schema.BeforeCreate) {
		callMethod(, func( interface{},  *gorm.DB) ( bool) {
			if .Statement.Schema.BeforeSave {
				if ,  := .(BeforeSaveInterface);  {
					 = true
					.AddError(.BeforeSave())
				}
			}

			if .Statement.Schema.BeforeCreate {
				if ,  := .(BeforeCreateInterface);  {
					 = true
					.AddError(.BeforeCreate())
				}
			}
			return 
		})
	}
}

// Create create hook
func ( *Config) func( *gorm.DB) {
	 := utils.Contains(.CreateClauses, "RETURNING")

	return func( *gorm.DB) {
		if .Error != nil {
			return
		}

		if .Statement.Schema != nil {
			if !.Statement.Unscoped {
				for ,  := range .Statement.Schema.CreateClauses {
					.Statement.AddClause()
				}
			}

			if  && len(.Statement.Schema.FieldsWithDefaultDBValue) > 0 {
				if ,  := .Statement.Clauses["RETURNING"]; ! {
					 := make([]clause.Column, 0, len(.Statement.Schema.FieldsWithDefaultDBValue))
					for ,  := range .Statement.Schema.FieldsWithDefaultDBValue {
						 = append(, clause.Column{Name: .DBName})
					}
					.Statement.AddClause(clause.Returning{Columns: })
				}
			}
		}

		if .Statement.SQL.Len() == 0 {
			.Statement.SQL.Grow(180)
			.Statement.AddClauseIfNotExists(clause.Insert{})
			.Statement.AddClause(ConvertToCreateValues(.Statement))

			.Statement.Build(.Statement.BuildClauses...)
		}

		 := !.DryRun && .Error == nil
		if ! {
			return
		}

		,  := hasReturning(, )
		if  {
			if ,  := .Statement.Clauses["ON CONFLICT"];  {
				if ,  := .Expression.(clause.OnConflict); .DoNothing {
					 |= gorm.ScanOnConflictDoNothing
				}
			}

			,  := .Statement.ConnPool.QueryContext(
				.Statement.Context, .Statement.SQL.String(), .Statement.Vars...,
			)
			if .AddError() == nil {
				defer func() {
					.AddError(.Close())
				}()
				gorm.Scan(, , )
			}

			return
		}

		,  := .Statement.ConnPool.ExecContext(
			.Statement.Context, .Statement.SQL.String(), .Statement.Vars...,
		)
		if  != nil {
			.AddError()
			return
		}

		.RowsAffected, _ = .RowsAffected()
		if .RowsAffected != 0 && .Statement.Schema != nil &&
			.Statement.Schema.PrioritizedPrimaryField != nil &&
			.Statement.Schema.PrioritizedPrimaryField.HasDefaultValue {
			,  := .LastInsertId()
			 :=  == nil &&  > 0
			if ! {
				.AddError()
				return
			}

			switch .Statement.ReflectValue.Kind() {
			case reflect.Slice, reflect.Array:
				if .LastInsertIDReversed {
					for  := .Statement.ReflectValue.Len() - 1;  >= 0; -- {
						 := .Statement.ReflectValue.Index()
						if reflect.Indirect().Kind() != reflect.Struct {
							break
						}

						,  := .Statement.Schema.PrioritizedPrimaryField.ValueOf(.Statement.Context, )
						if  {
							.AddError(.Statement.Schema.PrioritizedPrimaryField.Set(.Statement.Context, , ))
							 -= .Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
						}
					}
				} else {
					for  := 0;  < .Statement.ReflectValue.Len(); ++ {
						 := .Statement.ReflectValue.Index()
						if reflect.Indirect().Kind() != reflect.Struct {
							break
						}

						if ,  := .Statement.Schema.PrioritizedPrimaryField.ValueOf(.Statement.Context, );  {
							.AddError(.Statement.Schema.PrioritizedPrimaryField.Set(.Statement.Context, , ))
							 += .Statement.Schema.PrioritizedPrimaryField.AutoIncrementIncrement
						}
					}
				}
			case reflect.Struct:
				,  := .Statement.Schema.PrioritizedPrimaryField.ValueOf(.Statement.Context, .Statement.ReflectValue)
				if  {
					.AddError(.Statement.Schema.PrioritizedPrimaryField.Set(.Statement.Context, .Statement.ReflectValue, ))
				}
			}
		}
	}
}

// AfterCreate after create hooks
func ( *gorm.DB) {
	if .Error == nil && .Statement.Schema != nil && !.Statement.SkipHooks && (.Statement.Schema.AfterSave || .Statement.Schema.AfterCreate) {
		callMethod(, func( interface{},  *gorm.DB) ( bool) {
			if .Statement.Schema.AfterCreate {
				if ,  := .(AfterCreateInterface);  {
					 = true
					.AddError(.AfterCreate())
				}
			}

			if .Statement.Schema.AfterSave {
				if ,  := .(AfterSaveInterface);  {
					 = true
					.AddError(.AfterSave())
				}
			}
			return 
		})
	}
}

// ConvertToCreateValues convert to create values
func ( *gorm.Statement) ( clause.Values) {
	 := .DB.NowFunc()

	switch value := .Dest.(type) {
	case map[string]interface{}:
		 = ConvertMapToValuesForCreate(, )
	case *map[string]interface{}:
		 = ConvertMapToValuesForCreate(, *)
	case []map[string]interface{}:
		 = ConvertSliceOfMapToValuesForCreate(, )
	case *[]map[string]interface{}:
		 = ConvertSliceOfMapToValuesForCreate(, *)
	default:
		var (
			,  = .SelectAndOmitColumns(true, false)
			,         = .Get("gorm:update_track_time")
			                    bool
		)
		.Settings.Delete("gorm:update_track_time")

		 = clause.Values{Columns: make([]clause.Column, 0, len(.Schema.DBNames))}

		for ,  := range .Schema.DBNames {
			if  := .Schema.FieldsByDBName[]; !.HasDefaultValue || .DefaultValueInterface != nil {
				if ,  := []; ( && ) || (! && (! || .AutoCreateTime > 0 || .AutoUpdateTime > 0)) {
					.Columns = append(.Columns, clause.Column{Name: })
				}
			}
		}

		switch .ReflectValue.Kind() {
		case reflect.Slice, reflect.Array:
			 := .ReflectValue.Len()
			if  == 0 {
				.AddError(gorm.ErrEmptySlice)
				return
			}

			.SQL.Grow( * 18)
			.Vars = make([]interface{}, 0, *len(.Columns))
			.Values = make([][]interface{}, )

			 := map[*schema.Field][]interface{}{}
			for  := 0;  < ; ++ {
				 := reflect.Indirect(.ReflectValue.Index())
				if !.IsValid() {
					.AddError(fmt.Errorf("slice data #%v is invalid: %w", , gorm.ErrInvalidData))
					return
				}

				.Values[] = make([]interface{}, len(.Columns))
				for ,  := range .Columns {
					 := .Schema.FieldsByDBName[.Name]
					if .Values[][],  = .ValueOf(.Context, );  {
						if .DefaultValueInterface != nil {
							.Values[][] = .DefaultValueInterface
							.AddError(.Set(.Context, , .DefaultValueInterface))
						} else if .AutoCreateTime > 0 || .AutoUpdateTime > 0 {
							.AddError(.Set(.Context, , ))
							.Values[][], _ = .ValueOf(.Context, )
						}
					} else if .AutoUpdateTime > 0 &&  {
						.AddError(.Set(.Context, , ))
						.Values[][], _ = .ValueOf(.Context, )
					}
				}

				for ,  := range .Schema.FieldsWithDefaultDBValue {
					if ,  := [.DBName]; ( && ) || (! && !) {
						if ,  := .ValueOf(.Context, ); ! {
							if len([]) == 0 {
								[] = make([]interface{}, )
							}
							[][] = 
						}
					}
				}
			}

			for ,  := range  {
				.Columns = append(.Columns, clause.Column{Name: .DBName})
				for  := range .Values {
					if [] == nil {
						.Values[] = append(.Values[], .Dialector.DefaultValueOf())
					} else {
						.Values[] = append(.Values[], [])
					}
				}
			}
		case reflect.Struct:
			.Values = [][]interface{}{make([]interface{}, len(.Columns))}
			for ,  := range .Columns {
				 := .Schema.FieldsByDBName[.Name]
				if .Values[0][],  = .ValueOf(.Context, .ReflectValue);  {
					if .DefaultValueInterface != nil {
						.Values[0][] = .DefaultValueInterface
						.AddError(.Set(.Context, .ReflectValue, .DefaultValueInterface))
					} else if .AutoCreateTime > 0 || .AutoUpdateTime > 0 {
						.AddError(.Set(.Context, .ReflectValue, ))
						.Values[0][], _ = .ValueOf(.Context, .ReflectValue)
					}
				} else if .AutoUpdateTime > 0 &&  {
					.AddError(.Set(.Context, .ReflectValue, ))
					.Values[0][], _ = .ValueOf(.Context, .ReflectValue)
				}
			}

			for ,  := range .Schema.FieldsWithDefaultDBValue {
				if ,  := [.DBName]; ( && ) || (! && !) {
					if ,  := .ValueOf(.Context, .ReflectValue); ! {
						.Columns = append(.Columns, clause.Column{Name: .DBName})
						.Values[0] = append(.Values[0], )
					}
				}
			}
		default:
			.AddError(gorm.ErrInvalidData)
		}
	}

	if ,  := .Clauses["ON CONFLICT"];  {
		if ,  := .Expression.(clause.OnConflict); .UpdateAll {
			if .Schema != nil && len(.Columns) >= 1 {
				,  := .SelectAndOmitColumns(true, true)

				 := make([]string, 0, len(.Columns)-1)
				for ,  := range .Columns {
					if  := .Schema.LookUpField(.Name);  != nil {
						if ,  := [.DBName]; ( && ) || (! && !) {
							if !.PrimaryKey && (!.HasDefaultValue || .DefaultValueInterface != nil ||
								strings.EqualFold(.DefaultValue, "NULL")) && .AutoCreateTime == 0 {
								if .AutoUpdateTime > 0 {
									 := clause.Assignment{Column: clause.Column{Name: .DBName}, Value: }
									switch .AutoUpdateTime {
									case schema.UnixNanosecond:
										.Value = .UnixNano()
									case schema.UnixMillisecond:
										.Value = .UnixNano() / 1e6
									case schema.UnixSecond:
										.Value = .Unix()
									}

									.DoUpdates = append(.DoUpdates, )
								} else {
									 = append(, .Name)
								}
							}
						}
					}
				}

				.DoUpdates = append(.DoUpdates, clause.AssignmentColumns()...)
				if len(.DoUpdates) == 0 {
					.DoNothing = true
				}

				// use primary fields as default OnConflict columns
				if len(.Columns) == 0 {
					for ,  := range .Schema.PrimaryFields {
						.Columns = append(.Columns, clause.Column{Name: .DBName})
					}
				}
				.AddClause()
			}
		}
	}

	return 
}