package recordview

import (
	"dbweb/core"
	"fmt"

	"github.com/linlexing/dbx/data"
	"github.com/linlexing/dbx/pageselect"
	"github.com/linlexing/dbx/scan"
)

//RecordSelect 是用于返回sql的类，它包装了dbx.Select,不直接用Select是因为有些参数是指针型数据，不能直接序列化保存
type RecordSelect struct {
	p           *core.ElementHandleArgs
	DBName      string
	TableName   string
	ManualPage  bool
	SQL         string
	More        []string
	PKS         []string
	Conditions  []*pageselect.SQLCondition
	Limit       int
	Columns     []*DisplayColumn
	Order       []string //附加的排序定义，如果为空，则自动取Columns定义中的
	Divide      []string
	ColumnTypes pageselect.ColumnTypes
}

//getSelect 返回pageselect.SqlSelect
func (r *RecordSelect) getSelect() (sqlSelect *pageselect.PageSelect, hideCols []string) {
	db := core.LoadOuterDB(r.p.DB, r.DBName)
	sql := r.SQL
	cols := r.ColumnTypes
	manPage := r.ManualPage
	//如果只有表名，没有sql，则自动生成sql和columntypes
	if len(r.SQL) == 0 {
		sql = fmt.Sprintf(`<<if eq "oci8" .Driver>>
	<<if ge .Limit 0>>
	SELECT /*+ parallel(16) */ * FROM(
	<<end>>
	  SELECT <<if .Columns>><<.Columns>><<else>>*<<end>>
	  FROM %s wholesql
	  <<if .Where>>WHERE <<.Where>><<end>>
	  <<if .OrderBy>>ORDER BY <<.OrderBy>><<end>>
	<<if ge .Limit 0>>
	)WHERE ROWNUM<=<<.Limit>>
	<<end>>
<<else>>
	SELECT <<if .Columns>><<.Columns>><<else>>*<<end>>
	FROM %[1]s wholesql
	<<if .Where>>WHERE <<.Where>><<end>>
	<<if .OrderBy>>ORDER BY <<.OrderBy>><<end>>
	<<if ge .Limit 0>>LIMIT <<.Limit>><<end>>
<<end>>`, r.TableName)
		tab, err := data.OpenTable(db.DriverName(), db, r.TableName)
		if err != nil {
			core.LOG.Panic(err)
		}
		cols = tab.ColumnTypes
		manPage = true
	}
	sqlSelect = pageselect.NewPageSelect(sql, cols, manPage)
	sqlSelect.SQLRenderArgs = map[string]interface{}{
		"Driver":   db.DriverName(),
		"User":     r.p.User,
		"LSession": r.p.LSession,
		"More":     r.More,
		"PKS":      r.PKS,
	}
	order := r.Order
	if len(r.Columns) > 0 {
		hideCols = []string{}
		sqlSelect.Columns = []string{}
		for _, v := range r.Columns {
			sqlSelect.Columns = append(sqlSelect.Columns, v.Name)
			if v.Hidden {
				hideCols = append(hideCols, v.Name)
			}
		}

		//如果是首页，则参数order为空，需要提取定义中的排序顺序
		if len(order) == 0 {
			order = []string{}
			for _, v := range r.Columns {
				switch v.Order {
				case "+":
					order = append(order, v.Name)
				case "-":
					order = append(order, "-"+v.Name)
				}
			}
		}
	}
	//如果唯一的字段没有加入排序列表，则在最后加上
	for _, uqField := range r.PKS {
		beInsert := false
		for _, v := range order {
			//字段名称后缀*的，是非空字段，不需要Nulls first
			if v == uqField || v == "-"+uqField {
				beInsert = true
				break
			}
		}
		if !beInsert {
			order = append(order, uqField)
		}
	}
	sqlSelect.ManualPage = manPage
	sqlSelect.Conditions = r.Conditions
	sqlSelect.Divide = r.Divide
	sqlSelect.Limit = r.Limit + 1
	sqlSelect.Order = order
	//暂时只有主键放入，以后扩充
	sqlSelect.NotNullFields = r.PKS
	return
}

//RowCount 返回记录总数
func (r *RecordSelect) RowCount() (int64, error) {
	sqlSelect, _ := r.getSelect()
	db := core.LoadOuterDB(r.p.DB, r.DBName)
	return sqlSelect.RowCount(db, db.DriverName())
}

//QueryRows 返回查询结果
func (r *RecordSelect) QueryRows() (result []map[string]interface{},
	cols []*scan.ColumnType, err error) {
	sqlSelect, _ := r.getSelect()
	db := core.LoadOuterDB(r.p.DB, r.DBName)
	return sqlSelect.QueryRows(db.DriverName(), db)
}

//Total 返回汇总
func (r *RecordSelect) Total(columns []string) (map[string]interface{}, error) {
	sqlSelect, _ := r.getSelect()
	db := core.LoadOuterDB(r.p.DB, r.DBName)
	return sqlSelect.Total(db, db.DriverName(), columns...)
}

//BuildSQL 返回SQL
func (r *RecordSelect) BuildSQL() string {
	sqlSelect, _ := r.getSelect()
	db := core.LoadOuterDB(r.p.DB, r.DBName)

	str, err := sqlSelect.BuildSQL(db.DriverName())
	if err != nil {
		core.LOG.Panic(err)
	}
	return str
}

//DataOrderSQL 返回排序的SQL，所有记录
func (r *RecordSelect) DataOrderSQL() string {
	sqlSelect, _ := r.getSelect()
	sqlSelect.Limit = -1
	db := core.LoadOuterDB(r.p.DB, r.DBName)
	str, err := sqlSelect.BuildSQL(db.DriverName())
	if err != nil {
		core.LOG.Panic(err)
	}
	return str
}

//DataSQL 返回SQL，所有记录
func (r *RecordSelect) DataSQL() string {
	sqlSelect, _ := r.getSelect()
	sqlSelect.Limit = -1
	sqlSelect.Order = nil
	db := core.LoadOuterDB(r.p.DB, r.DBName)
	str, err := sqlSelect.BuildSQL(db.DriverName())
	if err != nil {
		fmt.Println("sql is:", sqlSelect.SQL)
		fmt.Println("mpage:", sqlSelect.ManualPage)
		core.LOG.Panic(err)
	}
	return str
}

//NewRecordSelect 实例化一RecordSelect，目的是关联上p参数
func NewRecordSelect(p *core.ElementHandleArgs) *RecordSelect {
	return &RecordSelect{p: p}
}
