package orm

import (
	
	

	
)

type CreateTableOptions struct {
	Varchar     int // replaces PostgreSQL data type `text` with `varchar(n)`
	Temp        bool
	IfNotExists bool

	// FKConstraints causes CreateTable to create foreign key constraints
	// for has one relations. ON DELETE hook can be added using tag
	// `pg:"on_delete:RESTRICT"` on foreign key field. ON UPDATE hook can be added using tag
	// `pg:"on_update:CASCADE"`
	FKConstraints bool
}

type CreateTableQuery struct {
	q   *Query
	opt *CreateTableOptions
}

var (
	_ QueryAppender = (*CreateTableQuery)(nil)
	_ QueryCommand  = (*CreateTableQuery)(nil)
)

func ( *Query,  *CreateTableOptions) *CreateTableQuery {
	return &CreateTableQuery{
		q:   ,
		opt: ,
	}
}

func ( *CreateTableQuery) () string {
	,  := .AppendQuery(defaultFmter, nil)
	if  != nil {
		panic()
	}
	return string()
}

func ( *CreateTableQuery) () QueryOp {
	return CreateTableOp
}

func ( *CreateTableQuery) () QueryCommand {
	return &CreateTableQuery{
		q:   .q.Clone(),
		opt: .opt,
	}
}

func ( *CreateTableQuery) () *Query {
	return .q
}

func ( *CreateTableQuery) ( []byte) ([]byte, error) {
	return .AppendQuery(dummyFormatter{}, )
}

func ( *CreateTableQuery) ( QueryFormatter,  []byte) ( []byte,  error) {
	if .q.stickyErr != nil {
		return nil, .q.stickyErr
	}
	if .q.tableModel == nil {
		return nil, errModelNil
	}

	 := .q.tableModel.Table()

	 = append(, "CREATE "...)
	if .opt != nil && .opt.Temp {
		 = append(, "TEMP "...)
	}
	 = append(, "TABLE "...)
	if .opt != nil && .opt.IfNotExists {
		 = append(, "IF NOT EXISTS "...)
	}
	,  = .q.appendFirstTable(, )
	if  != nil {
		return nil, 
	}
	 = append(, " ("...)

	for ,  := range .Fields {
		if  > 0 {
			 = append(, ", "...)
		}

		 = append(, .Column...)
		 = append(, " "...)
		 = .appendSQLType(, )
		if .hasFlag(NotNullFlag) {
			 = append(, " NOT NULL"...)
		}
		if .hasFlag(UniqueFlag) {
			 = append(, " UNIQUE"...)
		}
		if .Default != "" {
			 = append(, " DEFAULT "...)
			 = append(, .Default...)
		}
	}

	 = appendPKConstraint(, .PKs)
	 = appendUniqueConstraints(, )

	if .opt != nil && .opt.FKConstraints {
		for ,  := range .Relations {
			 = .appendFKConstraint(, , )
		}
	}

	 = append(, ")"...)

	if .PartitionBy != "" {
		 = append(, " PARTITION BY "...)
		 = append(, .PartitionBy...)
	}

	if .Tablespace != "" {
		 = .appendTablespace(, .Tablespace)
	}

	return , .q.stickyErr
}

func ( *CreateTableQuery) ( []byte,  *Field) []byte {
	if .UserSQLType != "" {
		return append(, .UserSQLType...)
	}
	if .opt != nil && .opt.Varchar > 0 &&
		.SQLType == "text" {
		 = append(, "varchar("...)
		 = strconv.AppendInt(, int64(.opt.Varchar), 10)
		 = append(, ")"...)
		return 
	}
	if .hasFlag(PrimaryKeyFlag) {
		return append(, pkSQLType(.SQLType)...)
	}
	return append(, .SQLType...)
}

func ( string) string {
	switch  {
	case pgTypeSmallint:
		return pgTypeSmallserial
	case pgTypeInteger:
		return pgTypeSerial
	case pgTypeBigint:
		return pgTypeBigserial
	}
	return 
}

func ( []byte,  []*Field) []byte {
	if len() == 0 {
		return 
	}

	 = append(, ", PRIMARY KEY ("...)
	 = appendColumns(, "", )
	 = append(, ")"...)
	return 
}

func ( []byte,  *Table) []byte {
	 := make([]string, 0, len(.Unique))
	for  := range .Unique {
		 = append(, )
	}
	sort.Strings()

	for ,  := range  {
		 = appendUnique(, .Unique[])
	}

	return 
}

func ( []byte,  []*Field) []byte {
	 = append(, ", UNIQUE ("...)
	 = appendColumns(, "", )
	 = append(, ")"...)
	return 
}

func ( *CreateTableQuery) ( QueryFormatter,  []byte,  *Relation) []byte {
	if .Type != HasOneRelation {
		return 
	}

	 = append(, ", FOREIGN KEY ("...)
	 = appendColumns(, "", .BaseFKs)
	 = append(, ")"...)

	 = append(, " REFERENCES "...)
	 = .FormatQuery(, string(.JoinTable.SQLName))
	 = append(, " ("...)
	 = appendColumns(, "", .JoinFKs)
	 = append(, ")"...)

	if  := onDelete(.BaseFKs);  != "" {
		 = append(, " ON DELETE "...)
		 = append(, ...)
	}

	if  := onUpdate(.BaseFKs);  != "" {
		 = append(, " ON UPDATE "...)
		 = append(, ...)
	}

	return 
}

func ( *CreateTableQuery) ( []byte,  types.Safe) []byte {
	 = append(, " TABLESPACE "...)
	 = append(, ...)
	return 
}

func ( []*Field) string {
	var  string
	for ,  := range  {
		if .OnDelete != "" {
			 = .OnDelete
			break
		}
	}
	return 
}

func ( []*Field) string {
	var  string
	for ,  := range  {
		if .OnUpdate != "" {
			 = .OnUpdate
			break
		}
	}
	return 
}