package report_approve

import (
	"eta/eta_mobile/utils"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/rdlucklib/rdluck_tools/paging"
	"strings"
	"time"
)

// ReportApproveFlow 报告审批流表
type ReportApproveFlow struct {
	ReportApproveFlowId int       `orm:"column(report_approve_flow_id);pk" description:"审批流ID"`
	FlowName            string    `description:"审批流名称"`
	ReportType          int       `description:"报告类型：1-中文研报；2-英文研报；3-智能研报"`
	ClassifyFirstId     int       `description:"一级分类ID"`
	ClassifySecondId    int       `description:"二级分类ID"`
	ClassifyThirdId     int       `description:"三级分类ID"`
	CurrVersion         int       `description:"当前版本号"`
	CreateTime          time.Time `description:"创建时间"`
	ModifyTime          time.Time `description:"修改时间"`
	Enabled             int       `description:"1:有效，0:禁用"`
}

var ReportApproveFlowCols = struct {
	ReportApproveFlowId string
	FlowName            string
	ReportType          string
	ClassifyFirstId     string
	ClassifySecondId    string
	ClassifyThirdId     string
	CurrVersion         string
	CreateTime          string
	ModifyTime          string
	Enabled             string
}{
	ReportApproveFlowId: "report_approve_flow_id",
	FlowName:            "flow_name",
	ReportType:          "report_type",
	ClassifyFirstId:     "classify_first_id",
	ClassifySecondId:    "classify_second_id",
	ClassifyThirdId:     "classify_third_id",
	CurrVersion:         "curr_version",
	CreateTime:          "create_time",
	ModifyTime:          "modify_time",
	Enabled:             "enabled",
}

func (m *ReportApproveFlow) TableName() string {
	return "report_approve_flow"
}

func (m *ReportApproveFlow) PrimaryId() string {
	return ReportApproveFlowCols.ReportApproveFlowId
}

func (m *ReportApproveFlow) Create() (err error) {
	o := orm.NewOrmUsingDB("rddp")
	id, err := o.Insert(m)
	if err != nil {
		return
	}
	m.ReportApproveFlowId = int(id)
	return
}

func (m *ReportApproveFlow) CreateMulti(items []*ReportApproveFlow) (err error) {
	if len(items) == 0 {
		return
	}
	o := orm.NewOrmUsingDB("rddp")
	_, err = o.InsertMulti(len(items), items)
	return
}

func (m *ReportApproveFlow) Update(cols []string) (err error) {
	o := orm.NewOrmUsingDB("rddp")
	_, err = o.Update(m, cols...)
	return
}

func (m *ReportApproveFlow) Del() (err error) {
	o := orm.NewOrmUsingDB("rddp")
	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
	_, err = o.Raw(sql, m.ReportApproveFlowId).Exec()
	return
}

func (m *ReportApproveFlow) MultiDel(menuIds []int) (err error) {
	if len(menuIds) == 0 {
		return
	}
	o := orm.NewOrmUsingDB("rddp")
	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.PrimaryId(), utils.GetOrmInReplace(len(menuIds)))
	_, err = o.Raw(sql, menuIds).Exec()
	return
}

func (m *ReportApproveFlow) GetItemById(id int) (item *ReportApproveFlow, err error) {
	o := orm.NewOrmUsingDB("rddp")
	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
	err = o.Raw(sql, id).QueryRow(&item)
	return
}

func (m *ReportApproveFlow) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *ReportApproveFlow, err error) {
	o := orm.NewOrmUsingDB("rddp")
	order := ``
	if orderRule != "" {
		order = ` ORDER BY ` + orderRule
	}
	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
	err = o.Raw(sql, pars).QueryRow(&item)
	return
}

func (m *ReportApproveFlow) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
	o := orm.NewOrmUsingDB("rddp")
	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
	err = o.Raw(sql, pars).QueryRow(&count)
	return
}

func (m *ReportApproveFlow) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*ReportApproveFlow, err error) {
	o := orm.NewOrmUsingDB("rddp")
	fields := strings.Join(fieldArr, ",")
	if len(fieldArr) == 0 {
		fields = `*`
	}
	order := `ORDER BY create_time DESC`
	if orderRule != "" {
		order = ` ORDER BY ` + orderRule
	}
	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
	_, err = o.Raw(sql, pars).QueryRows(&items)
	return
}

func (m *ReportApproveFlow) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*ReportApproveFlow, err error) {
	o := orm.NewOrmUsingDB("rddp")
	fields := strings.Join(fieldArr, ",")
	if len(fieldArr) == 0 {
		fields = `*`
	}
	order := `ORDER BY create_time DESC`
	if orderRule != "" {
		order = ` ORDER BY ` + orderRule
	}
	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
	return
}

// ReportApproveFlowItem 报告审批流信息
type ReportApproveFlowItem struct {
	ReportApproveFlowId int    `description:"审批流ID"`
	FlowName            string `description:"审批流名称"`
	ReportType          int    `description:"报告类型：1-中文研报；2-英文研报；3-智能研报"`
	ClassifyFirstId     int    `description:"一级分类ID"`
	ClassifySecondId    int    `description:"二级分类ID"`
	ClassifyThirdId     int    `description:"三级分类ID"`
	ReportClassify      string `description:"报告类型: XX研报/一级分类/二级分类"`
	CreateTime          string `description:"创建时间"`
	ModifyTime          string `description:"修改时间"`
}

// FormatReportApproveFlow2Item 格式化报告审批流
func FormatReportApproveFlow2Item(origin *ReportApproveFlow) (item *ReportApproveFlowItem) {
	item = new(ReportApproveFlowItem)
	if origin == nil {
		return
	}
	item.ReportApproveFlowId = origin.ReportApproveFlowId
	item.FlowName = origin.FlowName
	item.ReportType = origin.ReportType
	item.ClassifyFirstId = origin.ClassifyFirstId
	item.ClassifySecondId = origin.ClassifySecondId
	item.ClassifyThirdId = origin.ClassifyThirdId
	item.CreateTime = utils.TimeTransferString(utils.FormatDateTime, origin.CreateTime)
	item.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, origin.ModifyTime)
	return
}

// ReportApproveFlowAddReq 新增报告审批流请求体
type ReportApproveFlowAddReq struct {
	FlowName         string                     `description:"审批流名称"`
	ReportType       int                        `description:"报告类型：1-中文研报；2-英文研报；3-智能研报"`
	ClassifyFirstId  int                        `description:"一级分类ID"`
	ClassifySecondId int                        `description:"二级分类ID"`
	ClassifyThirdId  int                        `description:"三级分类ID"`
	Nodes            []ReportApproveNodeSaveReq `description:"审批节点信息"`
}

// ReportApproveFlowEditReq 编辑报告审批流请求体
type ReportApproveFlowEditReq struct {
	ReportApproveFlowId int `description:"审批流ID"`
	ReportApproveFlowAddReq
}

// ReportApproveFlowRemoveReq 删除报告审批流请求体
type ReportApproveFlowRemoveReq struct {
	ReportApproveFlowId int `description:"报告审批流ID"`
}

type ReportClassifyTreeItem struct {
	ClassifyId   int                       `description:"分类ID"`
	ClassifyName string                    `description:"分类名称"`
	ParentId     int                       `description:"父级ID"`
	HasFlow      bool                      `description:"是否已配置审批流"`
	Children     []*ReportClassifyTreeItem `description:"子分类"`
}

// CreateFlowAndNodes 新增审批流和节点
func (m *ReportApproveFlow) CreateFlowAndNodes(flowItem *ReportApproveFlow, nodeItems []*ReportApproveNode) (err error) {
	if flowItem == nil {
		err = fmt.Errorf("flow is nil")
		return
	}
	o := orm.NewOrmUsingDB("rddp")
	tx, e := o.Begin()
	if e != nil {
		err = fmt.Errorf("orm begin err: %s", e.Error())
		return
	}
	prevNodes := make([]*ReportApproveNode, 0)
	defer func() {
		if err != nil {
			_ = tx.Rollback()
			return
		}
		_ = tx.Commit()
		// 更新每个节点的下一个节点信息, 放在事务中会更新失败
		if e = m.UpdateNextNodes(prevNodes); e != nil {
			err = fmt.Errorf("UpdatePrevNodes err: %s", e.Error())
			return
		}
	}()

	lastId, e := tx.Insert(flowItem)
	if e != nil {
		err = fmt.Errorf("insert flow err: %s", e.Error())
		return
	}
	flowItem.ReportApproveFlowId = int(lastId)

	nodesLen := len(nodeItems)
	if nodesLen == 0 {
		return
	}
	prevId := 0
	prevNode := new(ReportApproveNode)
	for k, v := range nodeItems {
		v.ReportApproveFlowId = flowItem.ReportApproveFlowId
		v.PrevNodeId = prevId
		id, e := tx.Insert(v)
		if e != nil {
			err = fmt.Errorf("insert node err: %s", e.Error())
			return
		}
		v.ReportApproveNodeId = int(id)
		prevId = v.ReportApproveNodeId

		// 下一个节点
		if prevNode != nil && k > 0 && k < nodesLen {
			prevNode.NextNodeId = int(id)
			prevNodes = append(prevNodes, prevNode)
		}
		prevNode = v
	}
	return
}

func (m *ReportApproveFlow) UpdateNextNodes(nodes []*ReportApproveNode) (err error) {
	if len(nodes) == 0 {
		return
	}
	updateCols := []string{"NextNodeId"}
	for _, v := range nodes {
		e := v.Update(updateCols)
		if e != nil {
			err = fmt.Errorf("prev node update err: %s", e.Error())
			return
		}
	}
	return
}

// UpdateFlowAndNodes 更新审批流和节点
func (m *ReportApproveFlow) UpdateFlowAndNodes(flowItem *ReportApproveFlow, nodeItems []*ReportApproveNode) (err error) {
	if flowItem == nil {
		err = fmt.Errorf("flow is nil")
		return
	}
	o := orm.NewOrmUsingDB("rddp")
	tx, e := o.Begin()
	if e != nil {
		err = fmt.Errorf("orm begin err: %s", e.Error())
		return
	}
	prevNodes := make([]*ReportApproveNode, 0)
	defer func() {
		if err != nil {
			_ = tx.Rollback()
			return
		}
		_ = tx.Commit()
		// 更新每个节点的下一个节点信息, 放在事务中会更新失败
		if e = m.UpdateNextNodes(prevNodes); e != nil {
			err = fmt.Errorf("UpdatePrevNodes err: %s", e.Error())
			return
		}
	}()

	// 更新审批流
	updateCols := []string{"FlowName", "ReportType", "ClassifyFirstId", "ClassifySecondId", "ClassifyThirdId", "CurrVersion", "ModifyTime"}
	if e = flowItem.Update(updateCols); e != nil {
		err = fmt.Errorf("update flow err: %s", e.Error())
		return
	}

	// 新增节点(旧版的节点不删除, 根据版本号区分)
	nodesLen := len(nodeItems)
	if nodesLen == 0 {
		return
	}
	prevId := 0
	prevNode := new(ReportApproveNode)
	for k, v := range nodeItems {
		v.ReportApproveFlowId = flowItem.ReportApproveFlowId
		v.PrevNodeId = prevId
		id, e := tx.Insert(v)
		if e != nil {
			err = fmt.Errorf("insert node err: %s", e.Error())
			return
		}
		v.ReportApproveNodeId = int(id)
		prevId = v.ReportApproveNodeId

		// 下一个节点
		if prevNode != nil && k > 0 && k < nodesLen {
			prevNode.NextNodeId = int(id)
			prevNodes = append(prevNodes, prevNode)
		}
		prevNode = v
	}
	return
}

// ReportApproveFlowDetailItem 报告审批流详情信息
type ReportApproveFlowDetailItem struct {
	ReportApproveFlowItem `description:"审批流信息"`
	Nodes                 []*ReportApproveNodeItem `description:"节点信息"`
}

// FormatFlowAndNodesItem2Detail 格式化审批流详情
func FormatFlowAndNodesItem2Detail(flowItem *ReportApproveFlow, nodeItems []*ReportApproveNode) (detail *ReportApproveFlowDetailItem, err error) {
	if flowItem == nil {
		return
	}
	detail = new(ReportApproveFlowDetailItem)
	detail.ReportApproveFlowId = flowItem.ReportApproveFlowId
	detail.FlowName = flowItem.FlowName
	detail.ReportType = flowItem.ReportType
	detail.ClassifyFirstId = flowItem.ClassifyFirstId
	detail.ClassifySecondId = flowItem.ClassifySecondId
	detail.ClassifyThirdId = flowItem.ClassifyThirdId
	detail.CreateTime = utils.TimeTransferString(utils.FormatDateTime, flowItem.CreateTime)
	detail.ModifyTime = utils.TimeTransferString(utils.FormatDateTime, flowItem.ModifyTime)
	detail.Nodes = make([]*ReportApproveNodeItem, 0)
	for _, v := range nodeItems {
		t, e := FormatReportApproveNode2Item(v)
		if e != nil {
			err = fmt.Errorf("format node err: %s", e.Error())
			return
		}
		detail.Nodes = append(detail.Nodes, t)
	}
	return
}

// ReportApproveFlowListReq 审批流列表请求体
type ReportApproveFlowListReq struct {
	PageSize         int    `form:"PageSize"`
	CurrentIndex     int    `form:"CurrentIndex"`
	ReportType       int    `form:"ReportType" description:"报告类型：1-中文研报；2-英文研报；3-智能研报"`
	ClassifyFirstId  int    `form:"ClassifyFirstId" description:"一级分类ID"`
	ClassifySecondId int    `form:"ClassifySecondId" description:"二级分类ID"`
	ClassifyThirdId  int    `form:"ClassifyThirdId" description:"三级级分类ID"`
	Keyword          string `form:"Keyword" description:"关键词"`
	SortRule         int    `form:"SortRule" description:"排序方式: 1-正序; 2-倒序(默认)"`
}

// ReportApproveFlowListResp 审批流列表响应体
type ReportApproveFlowListResp struct {
	List   []*ReportApproveFlowItem
	Paging *paging.PagingItem `description:"分页数据"`
}
