package utils

import (
	"bytes"
	"errors"
	"fmt"
	"reflect"
	"regexp"
	"text/template"
)

type Driver string
type SqlCondition string

const (
	DM            Driver       = "dm"
	MySql         Driver       = "mysql"
	GroupUnit     SqlCondition = "GroupUnit"
	Distinct      SqlCondition = "Distinct"
	Order         SqlCondition = "Order"
	Delimiter     SqlCondition = "Delimiter"
	ConvertColumn SqlCondition = "ConvertColumn"
)

var TemplateMap = map[SqlCondition]map[Driver]string{
	GroupUnit: {
		MySql: `GROUP_CONCAT({{.Distinct}} {{.Column}} {{.Order}} SEPARATOR '{{.Delimiter}}')`,
		DM:    `LISTAGG({{.Distinct}} {{.Column}},'{{.Delimiter}}') WITHIN GROUP ({{.Order}})`,
	},
	ConvertColumn: {
		MySql: `CONVERT({{.ConvertColumn}} USING gbk )`,
		DM:    `{{.ConvertColumn}}`,
	},
}

var supportDriverMap = map[string]Driver{
	"mysql": MySql,
	"dm":    DM,
	//"postgres": Postgres,
}

type QueryParam struct {
	Driver        string
	Column        string
	Order         string
	Distinct      string
	Delimiter     string
	OrderField    string
	OrderRule     string
	ConvertColumn string `description:"Convert指令传递的clounm"`
	HasDistinct   bool
}
type SqlParam interface {
	GetParamName() string
	GetFormatConditionStr(param *QueryParam) string
}
type DistinctParam struct {
}

func (distinctParam *DistinctParam) GetParamName() string {
	return "Distinct"
}
func (distinctParam *DistinctParam) GetFormatConditionStr(param *QueryParam) string {
	if param.HasDistinct {
		return "DISTINCT"
	}
	return ""
}

type ConvertParam struct {
}

func (convertParam *ConvertParam) GetParamName() string {
	return "Convert"
}
func (convertParam *ConvertParam) GetFormatConditionStr(param *QueryParam) (sqlStr string) {
	dbDriver, _ := getDriverInstance(param.Driver)
	if param.ConvertColumn == "" {
		FileLog.Error("转换字段为空,无法生成聚合sql")
		return
	}
	var templateSqlStr string
	if _, ok := TemplateMap[ConvertColumn][dbDriver]; !ok {
		templateSqlStr = TemplateMap[ConvertColumn][MySql]
	} else {
		templateSqlStr = TemplateMap[ConvertColumn][dbDriver]
	}
	if templateSqlStr == "" {
		FileLog.Error("转换sql模板不存在,无法生成转换sql")
		return
	}
	templateSql, err := template.New("ConvertColumn").Parse(templateSqlStr)
	if err != nil {
		FileLog.Error("failed to parse template: %v", err)
		return
	}
	//反射获取结构体的值
	value := reflect.ValueOf(param)
	// 检查是否是指针
	if value.Kind() != reflect.Ptr {
		fmt.Println("请求参数必须是一个结构体")
		return
	}
	// 获取结构体的元素
	elem := value.Elem()
	// 检查是否是结构体
	if elem.Kind() != reflect.Struct {
		fmt.Println("请求参数必须是一个结构体")
		return
	}
	// 获取字段的值
	fieldValue := elem.FieldByName("ConvertColumn")
	// 检查字段是否存在
	if !fieldValue.IsValid() {
		fmt.Printf("Error: field %s not found\n", "ConvertColumn")
		return
	}
	// 检查字段是否可导出
	if !fieldValue.CanSet() {
		fmt.Printf("Error: field %s is not exported and cannot be set\n", "ConvertColumn")
		return
	}
	// 渲染模板
	var buf bytes.Buffer
	err = templateSql.Execute(&buf, param)
	if err != nil {
		fmt.Sprintf("执行模板填充失败: %v", err)
		return
	}
	sqlStr = buf.String()
	fmt.Printf("生成的准换编码语句为:%s\n", sqlStr)
	return sqlStr
}

var sqlGeneratorFactory = map[SqlCondition]SqlParam{
	// 添加支持的语法
	GroupUnit: &GroupUnitParam{
		supportGrams: []SqlCondition{
			Distinct,
			Order,
			Delimiter,
		},
	},
	Order:         &OrderParam{},
	Delimiter:     &DelimiterParam{},
	Distinct:      &DistinctParam{},
	ConvertColumn: &ConvertParam{},
}

type DelimiterParam struct {
}

func (delimiterParam *DelimiterParam) GetParamName() string {
	return "Delimiter"
}
func (delimiterParam *DelimiterParam) GetFormatConditionStr(param *QueryParam) string {
	if param.Delimiter == "" {
		return ","
	}
	return param.Delimiter
}

type OrderParam struct {
	Field string
	Rule  string
}

func (orderParam *OrderParam) GetParamName() string {
	return "Order"
}

func (orderParam *OrderParam) GetFormatConditionStr(param *QueryParam) string {
	if param.OrderField == "" {
		orderParam.Field = param.Column
	} else {
		orderParam.Field = param.OrderField
	}
	if param.OrderRule != "" {
		if param.OrderRule == "ASC" || param.OrderRule == "DESC" {
			orderParam.Rule = param.OrderRule
		}
	}
	return fmt.Sprintf("ORDER BY %s %s", orderParam.Field, orderParam.Rule)
}

// 高级语法聚合
type GroupUnitParam struct {
	supportGrams []SqlCondition
}

func (groupUnitParam *GroupUnitParam) GetParamName() string {
	return "GroupUnit"
}

func (groupUnitParam *GroupUnitParam) GetFormatConditionStr(param *QueryParam) (sqlStr string) {
	dbDriver, _ := getDriverInstance(param.Driver)
	if param.Column == "" {
		FileLog.Error("聚合字段为空,无法生成聚合sql")
		return
	}
	var templateSqlStr string
	if _, ok := TemplateMap[GroupUnit][dbDriver]; !ok {
		templateSqlStr = TemplateMap[GroupUnit][MySql]
	} else {
		templateSqlStr = TemplateMap[GroupUnit][dbDriver]
	}
	if templateSqlStr == "" {
		FileLog.Error("聚合sql模板不存在,无法生成聚合sql")
		return
	}
	templateSql, err := template.New("GroupUnit").Parse(templateSqlStr)
	if err != nil {
		FileLog.Error("failed to parse template: %v", err)
		return
	}
	//反射获取结构体的值
	value := reflect.ValueOf(param)
	// 检查是否是指针
	if value.Kind() != reflect.Ptr {
		fmt.Println("请求参数必须是一个结构体")
		return
	}
	// 获取结构体的元素
	elem := value.Elem()
	// 检查是否是结构体
	if elem.Kind() != reflect.Struct {
		fmt.Println("请求参数必须是一个结构体")
		return
	}
	for _, supportGram := range groupUnitParam.supportGrams {
		// 获取字段的值
		fieldValue := elem.FieldByName(string(supportGram))
		// 检查字段是否存在
		if !fieldValue.IsValid() {
			fmt.Printf("Error: field %s not found\n", supportGram)
			continue
		}
		// 检查字段是否可导出
		if !fieldValue.CanSet() {
			fmt.Printf("Error: field %s is not exported and cannot be set\n", supportGram)
			continue
		}
		newValue := sqlGeneratorFactory[supportGram].GetFormatConditionStr(param)
		// 检查新值的类型是否匹配
		newValueValue := reflect.ValueOf(newValue)
		if fieldValue.Type() != newValueValue.Type() {
			fmt.Printf("字段%s类型不匹配 : 期望的类型是 %s, 传入的类型为: %s", supportGram, fieldValue.Type(), newValueValue.Type())
			return
		}
		// 设置字段的值
		fieldValue.Set(newValueValue)
	}
	// 渲染模板
	var buf bytes.Buffer
	err = templateSql.Execute(&buf, param)
	if err != nil {
		fmt.Sprintf("执行模板填充失败: %v", err)
		return
	}
	sqlStr = buf.String()
	fmt.Printf("生成的聚合语句为:%s\n", sqlStr)
	return sqlStr
}

func GroupUnitFunc(driver string, column, delimiter string, columnOrder bool, orderField, orderRule string, hasDistinct bool) (sqlStr string) {
	dbDriver, _ := getDriverInstance(driver)
	if delimiter == "" {
		delimiter = ","
	}
	if column == "" {
		column = "[UNKNOWN COLUMN]"
	}
	//if tableAlia != "" {
	//	column = fmt.Sprintf("%s.%s", tableAlia, column)
	//}
	var sqlOrder, strDistinct string
	if hasDistinct {
		strDistinct = "DISTINCT"
	}
	if columnOrder && orderField == "" {
		orderField = column
	}
	switch dbDriver {
	case DM:
		if columnOrder {
			sqlOrder = fmt.Sprintf("WITHIN GROUP (ORDER BY %s %s)", orderField, orderRule)
		}
		sqlStr = fmt.Sprintf("LISTAGG(%s %s, '%s') %s", strDistinct, column, delimiter, sqlOrder)
	default:
		// 默认使用MySQL的语法
		if columnOrder {
			sqlOrder = fmt.Sprintf("ORDER BY %s %s", orderField, orderRule)
		}
		sqlStr = fmt.Sprintf("GROUP_CONCAT(%s %s %s SEPARATOR '%s')", strDistinct, column, sqlOrder, delimiter)
	}
	return sqlStr
}

func getDriverInstance(driver string) (dbDriver Driver, err error) {
	if driver == "" {
		dbDriver = supportDriverMap[DbDriverName]
	}
	if currentDriver, ok := supportDriverMap[driver]; !ok {
		err = errors.New("不支持的数据库驱动类型")
		return
	} else {
		dbDriver = currentDriver
	}
	return
}
func ReplaceDriverKeywords(driver string, sql string) string {
	dbDriver, _ := getDriverInstance(driver)
	rules := map[Driver]map[string]string{
		DM: {
			"admin":    `"admin"`,
			"value":    `"value"`,
			"exchange": `"exchange"`,
			"size":     `"size"`,
			// 查询的from可能会有个别地方是小写, 所以这里不加而是把字段的from统一改为*.from处理
			"a.from": `a."from"`,
			"b.from": `b."from"`,
			"g.from": `g."from"`,
		},
	}
	replacements, ok := rules[dbDriver]
	if !ok {
		return sql
	}
	for keyword, replace := range replacements {
		// 仅替换单独的单词,复合单词含关键词不管
		pattern := fmt.Sprintf(`\b%s\b`, regexp.QuoteMeta(keyword))
		re := regexp.MustCompile(pattern)
		sql = re.ReplaceAllString(sql, replace)
	}
	return sql
}

func GenerateQuerySql(gram SqlCondition, param *QueryParam) (sqlGenerator string) {
	if exec, ok := sqlGeneratorFactory[gram]; !ok {
		FileLog.Error("不支持的语法:%s", gram)
		return
	} else {
		sqlGenerator = exec.GetFormatConditionStr(param)
	}
	return
}