package admin

import (
	"gfast/app/model/admin/gen_table"
	"gfast/app/service/admin/gen_service"
	"gfast/app/service/admin/user_service"
	"gfast/library/response"
	"github.com/gogf/gf/encoding/gcompress"
	"github.com/gogf/gf/encoding/gjson"
	"github.com/gogf/gf/errors/gerror"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/net/ghttp"
	"github.com/gogf/gf/os/gfile"
	"github.com/gogf/gf/os/gview"
	"github.com/gogf/gf/text/gregex"
	"github.com/gogf/gf/text/gstr"
	"github.com/gogf/gf/util/gconv"
	"github.com/gogf/gf/util/grand"
	"github.com/gogf/gf/util/gvalid"
	"strings"
)

type Gen struct{}

// @Summary 查询数据库列表
// @Description 查询数据库列表
// @Tags 系统工具
// @Param data body gen_table.SelectPageReq true "data"
// @Success 0 {object} response.Response "{"code": 200, "data": [...]}"
// @Router /system/tools/gen/dataList [get]
// @Security
func (c *Gen) DataList(r *ghttp.Request) {
	var req *gen_table.SelectPageReq
	//获取参数
	if err := r.Parse(&req); err != nil {
		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
	}

	total, list, err := gen_service.SelectDbTableList(req)
	if err != nil {
		response.FailJson(true, r, err.Error())
	}
	response.SusJson(true, r, "ok", g.Map{
		"total": total,
		"list":  list,
	})
}

// @Summary 表列表
// @Description 表列表
// @Tags 系统工具
// @Param data body gen_table.SelectPageReq true "data"
// @Success 0 {object} response.Response "{"code": 200, "data": [...]}"
// @Router /system/tools/gen/tableList [post]
// @Security
func (c *Gen) TableList(r *ghttp.Request) {
	var req *gen_table.SelectPageReq
	//获取参数
	if err := r.Parse(&req); err != nil {
		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
	}
	total, list, err := gen_service.SelectListByPage(req)
	if err != nil {
		response.FailJson(true, r, err.Error())
	}
	response.SusJson(true, r, "ok", g.Map{
		"total": total,
		"list":  list,
	})
}

// @Summary 导入表结构操作
// @Description 导入表结构操作
// @Tags 系统工具
// @Param tables body string  true "tables"
// @Success 0 {object} response.Response "{"code": 200, "data": [...]}"
// @Router /system/tools/gen/importTableSave [post]
// @Security
func (c *Gen) ImportTableSave(r *ghttp.Request) {
	tables := r.GetString("tables")
	if tables == "" {
		response.FailJson(true, r, "请选择要导入的表格")
	}
	user := user_service.GetLoginAdminInfo(r)
	operName := user.UserName
	tableArr := strings.Split(tables, ",")
	tableList, err := gen_service.SelectDbTableListByNames(tableArr)
	if err != nil {
		response.FailJson(true, r, err.Error())
	}
	if tableList == nil {
		response.FailJson(true, r, "表信息不存在")
	}
	err = gen_service.ImportGenTable(tableList, operName)
	if err != nil {
		response.FailJson(true, r, err.Error())
	}
	response.SusJson(true, r, "导入数据表成功")
}

// @Summary 根据表格ID获取表格字段列表数据
// @Description 根据表格ID获取表格字段列表数据
// @Tags 系统工具
// @Param tableId body integer   true "tableId"
// @Success 0 {object} response.Response "{"code": 200, "data": [...]}"
// @Router /system/tools/gen/columnList [post]
// @Security
func (c *Gen) ColumnList(r *ghttp.Request) {
	tableId := r.GetInt64("tableId")
	if tableId == 0 {
		response.FailJson(true, r, "参数错误")
	}
	list, err := gen_service.SelectGenTableColumnListByTableId(tableId)
	if err != nil {
		response.FailJson(true, r, err.Error())
	}
	var tableInfo *gen_table.Entity
	var tableMap g.Map
	tableInfo, err = gen_service.GetTableInfoByTableId(tableId)
	tableMap = gconv.Map(tableInfo)
	//如果是树表则设置树表配置
	if tableInfo != nil && tableInfo.TplCategory == "tree" {
		options := gjson.New(tableInfo.Options)
		tableMap["tree_code"] = options.Get("tree_code")
		tableMap["tree_parent_code"] = options.Get("tree_parent_code")
		tableMap["tree_name"] = options.Get("tree_name")
	}

	res := g.Map{
		"rows": list,
		"info": tableMap,
	}
	response.SusJson(true, r, "ok", res)
}

// @Summary 编辑表格信息
// @Description 编辑表格信息
// @Tags 系统工具
// @Param data body gen_table.EditReq  true "data"
// @Success 0 {object} response.Response "{"code": 200, "data": [...]}"
// @Router /system/tools/gen/editSave [post]
// @Security
func (c *Gen) EditSave(r *ghttp.Request) {
	var req *gen_table.EditReq
	//获取参数
	if err := r.Parse(&req); err != nil {
		response.FailJson(true, r, err.(*gvalid.Error).FirstString())
	}
	userInfo := user_service.GetLoginAdminInfo(r)
	req.UserName = userInfo.UserName
	err := gen_service.SaveEdit(req)
	if err != nil {
		response.FailJson(true, r, err.Error())
	}
	response.SusJson(true, r, "设置成功")
}

// @Summary 删除表格数据
// @Description 删除表格数据
// @Tags 系统工具
// @Param ids body integer   true "ids[1,2,3...]"
// @Success 0 {object} response.Response "{"code": 200, "data": [...]}"
// @Router /system/tools/gen/delete [delete]
// @Security
func (c *Gen) Delete(r *ghttp.Request) {
	ids := r.GetInts("ids")
	if len(ids) == 0 {
		response.FailJson(true, r, "参数错误")
	}
	err := gen_service.Delete(ids)
	if err != nil {
		response.FailJson(true, r, err.Error())
	}
	response.SusJson(true, r, "删除成功")
}

// @Summary 代码生成预览
// @Description 代码生成预览
// @Tags 系统工具
// @Param tableId body integer   true "tableId"
// @Success 0 {object} response.Response "{"code": 200, "data": [...]}"
// @Router /system/tools/gen/preview [post]
// @Security
func (c *Gen) Preview(r *ghttp.Request) {
	tableId := r.GetInt64("tableId")
	if tableId == 0 {
		response.FailJson(true, r, "参数错误")
	}
	data, _, err := c.genData(tableId)
	if err != nil {
		response.FailJson(true, r, err.Error())
	}
	response.SusJson(true, r, "ok", data)
}

//下载生成的代码
func (c *Gen) BatchGenCode(r *ghttp.Request) {
	tableIds := r.GetString("tables")
	if tableIds == "" {
		response.FailJson(true, r, "请选择要生成的表")
	}
	ids := gstr.Split(tableIds, ",")
	dataFilePath := g.Cfg().GetString("adminInfo.dataDir")
	dataFileRange := grand.S(10)
	//生成文件
	for _, id := range ids {
		data, entity, err := c.genData(gconv.Int64(id))
		if err != nil {
			response.FailJson(true, r, err.Error())
		}
		pathMap := c.getPath(entity)
		for key, val := range data {
			switch key {
			case "vm/go/" + entity.BusinessName + "_controller.go.vm":
				err = gfile.PutContents(dataFilePath+"/gen/"+dataFileRange+"/go/"+pathMap["controller"], val)
				if err != nil {
					response.FailJson(true, r, err.Error())
				}
			case "vm/go/" + entity.BusinessName + "_service.go.vm":
				err = gfile.PutContents(dataFilePath+"/gen/"+dataFileRange+"/go/"+pathMap["service"], val)
				if err != nil {
					response.FailJson(true, r, err.Error())
				}
			case "vm/go/" + entity.BusinessName + "_model.go.vm":
				err = gfile.PutContents(dataFilePath+"/gen/"+dataFileRange+"/go/"+pathMap["model"], val)
				if err != nil {
					response.FailJson(true, r, err.Error())
				}
			case "vm/html/" + entity.BusinessName + "_api.js.vm":
				err = gfile.PutContents(dataFilePath+"/gen/"+dataFileRange+"/vue/"+pathMap["api"], val)
				if err != nil {
					response.FailJson(true, r, err.Error())
				}
			case "vm/html/" + entity.BusinessName + "_vue.js.vm":
				err = gfile.PutContents(dataFilePath+"/gen/"+dataFileRange+"/vue/"+pathMap["vue"], val)
				if err != nil {
					response.FailJson(true, r, err.Error())
				}
			}
		}
	}
	//打包
	err := gcompress.ZipPathWriter(dataFilePath+"/gen/"+dataFileRange, r.Response.Writer)
	if err != nil {
		response.FailJson(true, r, err.Error())
	}
	//删除生成的文件
	gfile.Remove(dataFilePath + "/gen/" + dataFileRange)
	//设置下载文件名
	r.Response.Header().Set("Content-Length", gconv.String(r.Response.BufferLength()))
	r.Response.Header().Set("Content-Type", "application/force-download")
	r.Response.Header().Set("Accept-Ranges", "bytes")
	r.Response.Header().Set("Content-Disposition", "attachment; filename=gfast.zip")
	r.Response.Buffer()
}

//获取生成文件的目录
func (c *Gen) getPath(entity *gen_table.EntityExtend) g.MapStrStr {
	controller := "app/controller/" + entity.ModuleName + "/" + entity.ClassName + ".go"
	service := "app/service/" + entity.ModuleName + "/" + entity.BusinessName + "_service/" + entity.ClassName + ".go"
	model := "app/model/" + entity.ModuleName + "/" + entity.BusinessName + "/" + entity.ClassName + ".go"
	vue := "views/" + entity.ModuleName + "/" + entity.BusinessName + "/index.vue"
	api := "api/" + entity.ModuleName + "/" + entity.BusinessName + ".js"
	return g.MapStrStr{
		"controller": controller,
		"service":    service,
		"model":      model,
		"vue":        vue,
		"api":        api,
	}
}

//获取生成数据
func (c *Gen) genData(tableId int64) (data g.MapStrStr, entity *gen_table.EntityExtend, err error) {
	entity, err = gen_service.SelectRecordById(tableId)
	if err != nil {
		return
	}
	if entity == nil {
		err = gerror.New("表格数据不存在")
		return
	}
	gen_service.SetPkColumn(entity, entity.Columns)
	controllerKey := "vm/go/" + entity.BusinessName + "_controller.go.vm"
	controllerValue := ""
	serviceKey := "vm/go/" + entity.BusinessName + "_service.go.vm"
	serviceValue := ""
	modelKey := "vm/go/" + entity.BusinessName + "_model.go.vm"
	modelValue := ""
	apiJsKey := "vm/html/" + entity.BusinessName + "_api.js.vm"
	apiJsValue := ""
	vueKey := "vm/html/" + entity.BusinessName + "_vue.js.vm"
	vueValue := ""

	view := gview.New()
	view.BindFuncMap(g.Map{
		"UcFirst": func(str string) string {
			return gstr.UcFirst(str)
		},
		"add": func(a, b int) int {
			return a + b
		},
	})
	view.SetConfigWithMap(g.Map{
		"Paths":      []string{"template"},
		"Delimiters": []string{"${", "}"},
	})
	//树形菜单选项
	var options g.Map
	if entity.TplCategory == "tree" {
		options = gjson.New(entity.Options).ToMap()
	}
	var tmpController string
	if tmpController, err = view.Parse("vm/go/"+entity.TplCategory+"/controller.template", g.Map{"table": entity}); err == nil {
		controllerValue = tmpController
	} else {
		return
	}
	var tmpService string
	if tmpService, err = view.Parse("vm/go/"+entity.TplCategory+"/service.template", g.Map{"table": entity, "options": options}); err == nil {
		serviceValue = tmpService
	} else {
		return
	}
	var tmpModel string
	if tmpModel, err = view.Parse("vm/go/"+entity.TplCategory+"/model.template", g.Map{"table": entity}); err == nil {
		modelValue = tmpModel
		modelValue, err = c.trimBreak(modelValue)
	} else {
		return
	}
	var tmpJs string
	if tmpJs, err = view.Parse("vm/html/js.template", g.Map{"table": entity}); err == nil {
		apiJsValue = tmpJs
	} else {
		return
	}
	var tmpVue string
	if tmpVue, err = view.Parse("vm/html/vue_"+entity.TplCategory+".template", g.Map{"table": entity, "options": options}); err == nil {
		vueValue = tmpVue
		vueValue, err = c.trimBreak(vueValue)
	} else {
		return
	}

	data = g.MapStrStr{
		modelKey:      modelValue,
		serviceKey:    serviceValue,
		controllerKey: controllerValue,
		apiJsKey:      apiJsValue,
		vueKey:        vueValue,
	}
	return
}

//剔除多余的换行
func (c *Gen) trimBreak(str string) (s string, err error) {
	var b []byte
	if b, err = gregex.Replace("(([\\s\t]*)\r?\n){2,}", []byte("$2\n"), []byte(str)); err == nil {
		s = gconv.String(b)
	}
	return
}
