package work_flow_service

import (
	"encoding/json"
	"gfast/app/model/admin/user"
	"gfast/app/model/admin/wf_flow_process"
	"gfast/app/model/admin/wf_run"
	"gfast/app/model/admin/wf_run_process"
	"github.com/gogf/gf/container/garray"
	"github.com/gogf/gf/database/gdb"
	"github.com/gogf/gf/encoding/gjson"
	"github.com/gogf/gf/errors/gerror"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/text/gstr"
	"github.com/gogf/gf/util/gconv"
)

//流程运行数据
type ProcessData struct {
	*wf_flow_process.Entity
	Todo     g.MapStrAny  `json:"todo"`
	UserInfo *user.Entity `json:"user_info"`
}

//获取流程下所有步骤信息
func ProcessAll(flowId int64) (total int64, list []*wf_flow_process.ProcessData, err error) {
	return wf_flow_process.ProcessAll(flowId)
}

//获取流程转出信息
func GetProcessStep(processInfo *wf_flow_process.ProcessData, processList []*wf_flow_process.ProcessData) (
	list []*wf_flow_process.ProcessStepData, err error) {
	if processInfo == nil || processInfo.ProcessTo == "" || processList == nil {
		return
	}
	processArr := garray.NewStrArrayFrom(gstr.Split(processInfo.ProcessTo, ","))
	for _, process := range processList {
		if processArr.Contains(gconv.String(process.Id)) {
			var con []string
			con, err = getProcessCondition(processInfo.Process.OutCondition, process.Id)
			list = append(list, &wf_flow_process.ProcessStepData{
				PrevId:      processInfo.Id,
				Id:          process.Id,
				ProcessName: process.ProcessName,
				ProcessType: process.Process.ProcessType,
				Condition:   con,
			})
		}
	}
	return
}

//获取转出条件
func getProcessCondition(condition string, id interface{}) ([]string, error) {
	if condition == "" {
		return nil, nil
	}
	j, err := gjson.DecodeToJson(condition)
	if err != nil {
		g.Log().Error(err)
		return nil, gerror.New("转换转出条件失败")
	}
	return j.GetStrings(gconv.String(id) + ".condition"), nil
}

//添加流程步骤
func ProcessAdd(flowId int64) error {
	return wf_flow_process.ProcessAdd(flowId)
}

//保存流程设计
func SaveProcess(req *wf_flow_process.SaveProcessReqBatch) error {
	return wf_flow_process.SaveProcess(req)
}

//获取流程管理表字段信息
func GetFlowTableFields(tableName string) (fields []*wf_flow_process.FlowTableField, err error) {
	//表前缀
	dbPrefix := g.DB().GetPrefix()
	//数据库
	database := g.Cfg().GetString("database.name")
	return wf_flow_process.GetFlowTableFields(dbPrefix, database, tableName)
}

//pid 步骤ID wf_flow_process 主键
//runId 运行步骤ID wf_run 主键
func GetProcessInfo(pid, runId uint) (data *ProcessData, err error) {
	var flowProcessInfo *wf_flow_process.Entity
	flowProcessInfo, err = wf_flow_process.GetProcessInfoById(pid)
	if err != nil {
		return
	}
	if flowProcessInfo == nil {
		err = gerror.New("不存在流程信息")
		return
	}
	data = &ProcessData{
		Entity: flowProcessInfo,
	}
	if flowProcessInfo.AutoPerson == 3 { //自由选择
		data.Todo = g.MapStrAny{"ids": gstr.Split(flowProcessInfo.RangeUserIds, ","), "text": gstr.Split(flowProcessInfo.RangeUserText, ",")}
	} else if flowProcessInfo.AutoPerson == 4 { //办理人员
		data.Todo = g.MapStrAny{"text": flowProcessInfo.AutoSponsorText}
	} else if flowProcessInfo.AutoPerson == 5 { //办理部门
		data.Todo = g.MapStrAny{"text": flowProcessInfo.AutoRoleText}
	} else if flowProcessInfo.AutoPerson == 6 { //事务接受
		var runInfo *wf_run.Entity
		runInfo, err = wf_run.GetRunById(runId)
		if err != nil {
			return
		}
		if runInfo == nil {
			err = gerror.New("不存在运行状态信息")
			return
		}
		var userId interface{}
		userId, err = GetBilValue(runInfo.FromTable, runInfo.FromId, flowProcessInfo.WorkText)
		if err != nil {
			return
		}
		if userId == nil {
			err = gerror.New("获取事务接受用户ID失败，请检测流程设计是否设置的是用户ID字段")
			return
		}
		var userInfo *user.Entity
		userInfo, err = user.GetUserById(gconv.Uint64(userId))
		if err != nil {
			return
		}
		data.Todo = g.MapStrAny{"text": userInfo.UserNickname}
		data.UserInfo = userInfo
	}
	return
}

//同步步骤信息
func GetProcessInfos(ids []uint, runId uint) (datas []*ProcessData, err error) {
	var list []*wf_flow_process.Entity
	list, err = wf_flow_process.GetProcessInfosByIds(ids)
	if err != nil {
		return
	}
	datas = make([]*ProcessData, len(list))
	for k, v := range list {
		var todo g.MapStrAny
		var userInfo *user.Entity
		if v.AutoPerson == 3 { //自由选择 办理人员
			todo = g.MapStrAny{
				"ids":  gstr.Split(v.AutoSponsorIds, ","),
				"text": gstr.Split(v.AutoSponsorText, ","),
			}
		} else if v.AutoPerson == 4 { //办理人员
			todo = g.MapStrAny{"text": v.AutoSponsorText}
		} else if v.AutoPerson == 5 { //办理部门
			todo = g.MapStrAny{"text": v.AutoRoleText}
		} else if v.AutoPerson == 6 { //事务接受
			var runInfo *wf_run.Entity
			runInfo, err = wf_run.GetRunById(runId)
			if err != nil {
				return
			}
			if runInfo == nil {
				err = gerror.New("不存在运行状态信息")
				return
			}
			var userId interface{}
			userId, err = GetBilValue(runInfo.FromTable, runInfo.FromId, v.WorkText)
			if err != nil {
				return
			}
			if userId == nil {
				err = gerror.New("获取事务接受用户ID失败，请检测流程设计是否设置的是用户ID字段")
				return
			}
			userInfo, err = user.GetUserById(gconv.Uint64(userId))
			if err != nil {
				return
			}
			todo = g.MapStrAny{"text": userInfo.UserNickname}
		}
		datas[k] = &ProcessData{
			Entity:   v,
			Todo:     todo,
			UserInfo: userInfo,
		}
	}
	return
}

//获取事务接受信息
func GetBilValue(fromTable string, fromId int, workText string) (value interface{}, err error) {
	var rec gdb.Record
	rec, err = GetBill(fromId, fromTable)
	if err != nil {
		return
	}
	value = rec[workText]
	return
}

//获取工作流业务表信息
func GetBill(fromId int, fromTable string) (rec gdb.Record, err error) {
	rec, err = g.DB().Table(fromTable).FindOne(fromId)
	if err != nil {
		g.Log().Error(err)
		err = gerror.New("获取工作里业务数据失败")
		return
	}
	return
}

//更新业务表信息
func UpdateBill(wfFid int, wfType string, statusField string, status int, tx *gdb.TX) error {
	_, err := tx.Table(wfType).WherePri(wfFid).Update(g.Map{
		statusField: status,
	})
	if err != nil {
		g.Log().Error(err)
		return gerror.New("更新单据信息失败")
	}
	return nil
}

//删除流程节点
func ProcessDelete(req *wf_flow_process.DeleteProcessReq) error {
	return wf_flow_process.ProcessDelete(req)
}

//清空节点
func ProcessDeleteAll(flowId int) error {
	_, err := wf_flow_process.Model.Where("flow_id", flowId).Delete()
	if err != nil {
		g.Log().Error(err)
		return gerror.New("删除失败")
	}
	return nil
}

//获取下个审批流信息
//wfType 单据表
//wfFid 单据id
//pid 流程id
//runId 运行id
func GetNexProcessInfo(wfType string, wfFid uint, pid uint, runId uint) ([]*ProcessData, error) {
	if pid == 0 {
		return nil, nil
	}
	nex, err := wf_flow_process.GetProcessInfoById(pid)
	if err != nil {
		return nil, err
	}
	var process *ProcessData
	var processes []*ProcessData
	//先判断下上一个流程是什么模式
	if nex.ProcessTo != "" {
		//下一个流程的下一步
		nexPidStr := gstr.Split(nex.ProcessTo, ",")
		nexPid := make([]uint, len(nexPidStr))
		for k, v := range nexPidStr {
			nexPid[k] = gconv.Uint(v)
		}
		//下一个流程转出条件
		var outCondition g.MapStrAny
		err = json.Unmarshal([]byte(nex.OutCondition), &outCondition)
		if err != nil {
			outCondition = g.MapStrAny{}
		}
		switch nex.WfMode {
		case 0: //单一模式
			process, err = GetProcessInfo(gconv.Uint(nex.ProcessTo), runId)
			if err != nil {
				return nil, err
			}
			processes = append(processes, process)
		case 1: //多个审批流
			var nextProcessId uint
			for key, val := range outCondition {
				mapVal := gconv.Map(val)
				condition := gstr.Join(gconv.SliceStr(mapVal["condition"]), " ")
				//根据条件寻找匹配符合的工作流id
				if gstr.ContainsI(condition, "include") {
					condition = gstr.ReplaceI(condition, "include", " REGEXP ")
				}
				info, err := g.DB().Table(wfType).Where(condition).WherePri(wfFid).FindOne()
				if err != nil {
					g.Log().Error(err)
					return nil, gerror.New("获取转出条件对应的审批信息失败")
				}
				if info != nil {
					nextProcessId = gconv.Uint(key)
					break
				}
			}
			if nextProcessId == 0 { //没有权限
				return nil, nil
			}
			process, err = GetProcessInfo(nextProcessId, runId)
			if err != nil {
				return nil, err
			}
			processes = append(processes, process)
		case 2: //同步模式
			processes, err = GetProcessInfos(nexPid, runId)
			if err != nil {
				return nil, err
			}
		}
	} else {
		process = &ProcessData{
			Entity: &wf_flow_process.Entity{
				Id:          0,
				AutoPerson:  0,
				ProcessName: "END",
			},
			Todo: g.MapStrAny{"text": "结束"},
		}
		processes = append(processes, process)
	}
	return processes, nil
}

func GetPreProcessInfo(runId uint) (map[int]string, error) {
	var pre []*wf_flow_process.Entity
	preRun, err := wf_run_process.GetProcessById(runId)
	if err != nil {
		return nil, err
	}
	//获取本流程中小于本次ID的步骤信息
	var preP []*wf_run_process.Entity
	preP, err = wf_run_process.GetProcessLtId(preRun)
	if err != nil {
		return nil, err
	}
	//遍历获取小于本次ID中的相关步骤
	for _, v := range preP {
		wfp, err := wf_flow_process.GetProcessInfoById(v.RunFlowProcess)
		if err != nil {
			return nil, err
		}
		pre = append(pre, wfp)
	}
	preMap := make(map[int]string, 5)
	preMap[0] = "退回制单人修改"
	if len(pre) > 0 {
		for _, v := range pre {
			todo := ""
			if v.AutoPerson == 4 { //办理人员
				todo = v.AutoSponsorText
			} else if v.AutoPerson == 5 { //办理部门
				todo = v.AutoRoleText
			}
			preMap[v.Id] = v.ProcessName + "(" + todo + ")"
		}
	}
	return preMap, nil
}

//保存流程节点属性
func SaveProcessAttr(req *wf_flow_process.SaveAttrReq) error {
	if req == nil {
		return gerror.New("参数错误")
	}
	processCondition := gstr.Split(req.ProcessCondition, ",")
	outCondition := make(g.MapStrAny, 10)
	if len(processCondition) > 1 && req.WfMode == "1" {
		return gerror.New(msgNoAction)
	}
	ocbt, _ := json.Marshal(outCondition)
	entity, err := wf_flow_process.FindOne(req.ProcessId)
	if err != nil {
		g.Log().Error(err)
		return gerror.New("获取流程信息失败")
	}
	style := gjson.New(nil)
	style.Set("width", req.StyleWidth)
	style.Set("height", req.StyleHeight)
	style.Set("color", "#0e76a8")

	entity.ProcessName = req.ProcessName
	entity.ProcessType = req.ProcessType
	entity.AutoPerson = gconv.Uint(req.AutoPerson)
	entity.WfMode = gconv.Uint(req.WfMode)
	entity.WfAction = req.WfAction
	entity.AutoSponsorIds = req.AutoSponsorIds
	entity.AutoSponsorText = req.AutoSponsorText
	entity.AutoRoleIds = req.AutoRoleIds
	entity.AutoRoleText = req.AutoRoleText
	entity.RangeUserIds = req.RangeUserIds
	entity.RangeUserText = req.RangeUserText
	entity.WorkText = req.WorkText
	entity.WorkIds = req.WorkIds
	entity.WorkMsg = req.WorkMsg
	entity.WorkSql = req.WorkSql
	entity.IsSing = gconv.Uint(req.IsSing)
	entity.IsBack = gconv.Uint(req.IsBack)
	entity.OutCondition = string(ocbt)
	entity.Style = style.MustToJsonString()
	_, err = wf_flow_process.Model.Save(entity)
	if err != nil {
		g.Log().Error(err)
		return gerror.New("保存失败")
	}
	return nil
}

//获取流程步骤第一步
func getFirstProcess(processes []*wf_flow_process.Entity) *wf_flow_process.Entity {
	//找到 流程第一步
	var firstProcess *wf_flow_process.Entity
	for _, process := range processes {
		if process.ProcessType == "is_one" {
			firstProcess = process
			break
		}
	}
	return firstProcess
}

//获取步骤所有下级步骤
func GetAllNextProcessIds(id uint) (ids []uint, err error) {
	processData := ([]*wf_flow_process.ProcessData)(nil)
	processData, err = GetAllProcessesByProcessId(id)
	if err != nil {
		return
	}
	ids = GetNextProcessesById(id, processData)
	return
}

//获取步骤所有上级步骤
func GetAllPreProcessIds(id uint) (ids []uint, err error) {
	processData := ([]*wf_flow_process.ProcessData)(nil)
	processData, err = GetAllProcessesByProcessId(id)
	if err != nil {
		return
	}
	ids = GetPreProcessesById(id, processData)
	return
}

//获取对应步骤所属流程的所有步骤数据
func GetAllProcessesByProcessId(id uint) (processData []*wf_flow_process.ProcessData, err error) {
	process := (*wf_flow_process.Entity)(nil)
	process, err = wf_flow_process.GetProcessInfoById(id)
	if err != nil {
		return
	}
	if process == nil {
		err = gerror.New("流程步骤信息不存在")
		return
	}
	//获取流程下所有步骤
	_, processData, err = wf_flow_process.ProcessAll(gconv.Int64(process.FlowId))
	return
}

//获取所有上级步骤切片id
func GetPreProcessesById(id uint, processData []*wf_flow_process.ProcessData) (ids []uint) {
	ids = make([]uint, 0, len(processData))
	for _, v := range processData {
		processTo := gstr.Split(v.ProcessTo, ",")
		processToArr := garray.NewStrArrayFrom(processTo)
		if processToArr.Contains(gconv.String(id)) {
			id := gconv.Uint(v.Id)
			ids = append(ids, id)
			idsChd := GetPreProcessesById(id, processData)
			if len(idsChd) > 0 {
				ids = append(ids, idsChd...)
			}
		}
	}
	return
}

//获取所有下级步骤id切片
func GetNextProcessesById(id uint, processData []*wf_flow_process.ProcessData) (ids []uint) {
	ids = make([]uint, 0, len(processData))
	for _, v := range processData {
		if id == gconv.Uint(v.Id) {
			processTo := gstr.Split(v.ProcessTo, ",")
			for _, v := range processTo {
				id := gconv.Uint(v)
				if id == 0 {
					continue
				}
				ids = append(ids, id)
				idsChd := make([]uint, 0, len(processData))
				idsChd = GetNextProcessesById(id, processData)
				if len(idsChd) > 0 {
					ids = append(ids, idsChd...)
				}
			}
		}
	}
	return
}
