// 工作流模块 HTTP Handler
package workflow

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"

	"com.sclktx/m/v2/internal/common/model"
	"com.sclktx/m/v2/internal/common/response"
	"com.sclktx/m/v2/internal/common/utils"
	"com.sclktx/m/v2/internal/pkg/dingtalk"
	"com.sclktx/m/v2/internal/pkg/wechat/templates"

	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
)

// Handler 工作流处理器
type Handler struct {
	db       *gorm.DB
	engine   *Engine
	wxSend   func(openid, templateID string, data map[string]string, page string) error
	dingTalk *dingtalk.Client
}

// NewHandler 创建工作流处理器
func NewHandler(db *gorm.DB, wxSend func(openid, templateID string, data map[string]string, page string) error, dingTalk *dingtalk.Client) *Handler {
	return &Handler{
		db:       db,
		engine:   NewEngine(db),
		wxSend:   wxSend,
		dingTalk: dingTalk,
	}
}

// ==================== 请求/响应结构 ====================

// CreateDefinitionReq 创建流程定义请求
type CreateDefinitionReq struct {
	ProcessName  string `json:"process_name" binding:"required"`
	ProcessCode  string `json:"process_code" binding:"required"`
	Source       string `json:"source"`
	Description  string `json:"description"`
	RevokeEvents string `json:"revoke_events"`
	NodesJSON    string `json:"nodes_json"`
}

// UpdateDefinitionReq 更新流程定义请求
type UpdateDefinitionReq struct {
	ProcessName  string `json:"process_name"`
	Source       string `json:"source"`
	Description  string `json:"description"`
	IsActive     *bool  `json:"is_active"`
	RevokeEvents string `json:"revoke_events"`
	NodesJSON    string `json:"nodes_json"`
}

// StartInstanceReq 启动流程实例请求
type StartInstanceReq struct {
	ProcessCode  string                 `json:"process_code" binding:"required"`
	BusinessType string                 `json:"business_type" binding:"required"`
	BusinessID   uint                   `json:"business_id" binding:"required"`
	Variables    map[string]interface{} `json:"variables"`
}

// TaskActionReq 任务操作请求
type TaskActionReq struct {
	Comment string `json:"comment"`
}

// ==================== 路由注册 ====================

// RegisterRoutes 注册工作流路由（需要 JWT 认证）
func (h *Handler) RegisterRoutes(router *gin.RouterGroup) {
	// 流程定义（管理员操作）
	router.GET("/workflow/definitions", h.ListDefinitions)
	router.GET("/workflow/definitions/:id", h.GetDefinition)
	router.POST("/workflow/definitions", h.CreateDefinition)
	router.PUT("/workflow/definitions/:id", h.UpdateDefinition)
	router.DELETE("/workflow/definitions/:id", h.DeleteDefinition)

	// 流程实例
	router.POST("/workflow/instances", h.StartInstance)
	router.GET("/workflow/instances", h.ListInstances)
	router.GET("/workflow/instances/:id", h.GetInstanceDetail)

	// 任务
	router.GET("/workflow/tasks/pending", h.GetPendingTasks)
	router.POST("/workflow/tasks/:id/approve", h.ApproveTask)
	router.POST("/workflow/tasks/:id/reject", h.RejectTask)
}

// ==================== 流程定义管理 ====================

// ListDefinitions 获取流程定义列表
// @Summary      获取流程定义列表
// @Description  获取所有流程定义列表
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        page      query int    false "页码" default(1)
// @Param        page_size query int    false "每页条数" default(10)
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/definitions [get]
func (h *Handler) ListDefinitions(c *gin.Context) {
	page, pageSize := utils.ParsePagination(c)

	var defs []model.ProcessDefinition
	var total int64

	query := h.db.Model(&model.ProcessDefinition{})
	query.Count(&total)
	query.Offset(utils.GetOffset(page, pageSize)).
		Limit(pageSize).
		Order("created_at DESC").
		Find(&defs)

	response.SuccessPage(c, defs, total, page, pageSize)
}

// GetDefinition 获取流程定义详情
// @Summary      获取流程定义详情
// @Description  根据ID获取流程定义详情
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        id path uint true "流程定义ID"
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/definitions/{id} [get]
func (h *Handler) GetDefinition(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	var def model.ProcessDefinition
	if err := h.db.First(&def, id).Error; err != nil {
		response.NotFound(c, "流程定义不存在")
		return
	}

	response.Success(c, def)
}

// CreateDefinition 创建流程定义
// @Summary      创建流程定义
// @Description  创建一个新的流程定义（管理员操作）
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        body body CreateDefinitionReq true "创建流程定义请求"
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/definitions [post]
func (h *Handler) CreateDefinition(c *gin.Context) {
	var req CreateDefinitionReq
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	// 检查编码唯一性
	var existCount int64
	h.db.Model(&model.ProcessDefinition{}).Where("process_code = ?", req.ProcessCode).Count(&existCount)
	if existCount > 0 {
		response.BadRequest(c, "流程编码已存在")
		return
	}

	def := model.ProcessDefinition{
		ProcessName:  req.ProcessName,
		ProcessCode:  req.ProcessCode,
		Source:       req.Source,
		Description:  req.Description,
		IsActive:     true,
		RevokeEvents: req.RevokeEvents,
		NodesJSON:    req.NodesJSON,
	}

	if err := h.db.Create(&def).Error; err != nil {
		response.InternalError(c, "创建失败")
		return
	}

	response.SuccessWithMessage(c, "创建成功", def)
}

// UpdateDefinition 更新流程定义
// @Summary      更新流程定义
// @Description  更新指定流程定义的信息（管理员操作）
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        id   path uint              true "流程定义ID"
// @Param        body body UpdateDefinitionReq true "更新流程定义请求"
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/definitions/{id} [put]
func (h *Handler) UpdateDefinition(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	var def model.ProcessDefinition
	if err := h.db.First(&def, id).Error; err != nil {
		response.NotFound(c, "流程定义不存在")
		return
	}

	var req UpdateDefinitionReq
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	updates := map[string]interface{}{}
	if req.ProcessName != "" {
		updates["process_name"] = req.ProcessName
	}
	if req.Source != "" {
		updates["source"] = req.Source
	}
	if req.Description != "" {
		updates["description"] = req.Description
	}
	if req.IsActive != nil {
		updates["is_active"] = *req.IsActive
	}
	if req.RevokeEvents != "" {
		updates["revoke_events"] = req.RevokeEvents
	}
	if req.NodesJSON != "" {
		updates["nodes_json"] = req.NodesJSON
	}

	if len(updates) > 0 {
		if err := h.db.Model(&def).Updates(updates).Error; err != nil {
			response.InternalError(c, "更新失败")
			return
		}
	}

	response.SuccessWithMessage(c, "更新成功", nil)
}

// DeleteDefinition 删除流程定义
// @Summary      删除流程定义
// @Description  删除指定的流程定义（管理员操作，存在运行中的实例时无法删除）
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        id path uint true "流程定义ID"
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/definitions/{id} [delete]
func (h *Handler) DeleteDefinition(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	// 检查是否有运行中的实例
	var activeCount int64
	h.db.Model(&model.ProcessInstance{}).Where("process_def_id = ? AND status = 0", id).Count(&activeCount)
	if activeCount > 0 {
		response.BadRequest(c, "存在运行中的流程实例，无法删除")
		return
	}

	if err := h.db.Delete(&model.ProcessDefinition{}, id).Error; err != nil {
		response.InternalError(c, "删除失败")
		return
	}

	response.SuccessWithMessage(c, "删除成功", nil)
}

// ==================== 流程实例管理 ====================

// StartInstance 启动流程实例
// @Summary      启动流程实例
// @Description  根据流程定义启动一个新的流程实例
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        body body StartInstanceReq true "启动流程实例请求"
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/instances [post]
func (h *Handler) StartInstance(c *gin.Context) {
	var req StartInstanceReq
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	// 查找流程定义
	var def model.ProcessDefinition
	if err := h.db.Where("process_code = ?", req.ProcessCode).First(&def).Error; err != nil {
		response.NotFound(c, "流程定义不存在")
		return
	}

	userID := utils.GetUserID(c)

	instance, err := h.engine.StartInstance(def.ID, req.BusinessType, req.BusinessID, userID, req.Variables)
	if err != nil {
		response.InternalError(c, err.Error())
		return
	}

	response.SuccessWithMessage(c, "启动成功", instance)
}

// ListInstances 获取流程实例列表
// @Summary      获取流程实例列表
// @Description  获取所有流程实例列表，可按业务类型和状态筛选
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        business_type query string false "业务类型"
// @Param        status        query int    false "实例状态"
// @Param        page          query int    false "页码" default(1)
// @Param        page_size     query int    false "每页条数" default(10)
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/instances [get]
func (h *Handler) ListInstances(c *gin.Context) {
	page, pageSize := utils.ParsePagination(c)
	businessType := c.Query("business_type")
	businessIDStr := c.Query("business_id")
	statusStr := c.Query("status")

	var instances []model.ProcessInstance
	var total int64

	query := h.db.Model(&model.ProcessInstance{}).
		Preload("ProcessDef").
		Preload("Starter")
	if businessType != "" {
		query = query.Where("business_type = ?", businessType)
	}
	if businessIDStr != "" {
		businessID, _ := strconv.ParseUint(businessIDStr, 10, 64)
		if businessID > 0 {
			query = query.Where("business_id = ?", businessID)
		}
	}
	if statusStr != "" {
		status, _ := strconv.Atoi(statusStr)
		query = query.Where("status = ?", status)
	}

	query.Count(&total)
	query.Offset(utils.GetOffset(page, pageSize)).
		Limit(pageSize).
		Order("created_at DESC").
		Find(&instances)

	response.SuccessPage(c, instances, total, page, pageSize)
}

// GetInstanceDetail 获取流程实例详情（含任务列表）
// @Summary      获取流程实例详情
// @Description  获取流程实例详情，包含关联的任务列表
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        id path uint true "流程实例ID"
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/instances/{id} [get]
func (h *Handler) GetInstanceDetail(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	var instance model.ProcessInstance
	if err := h.db.Preload("ProcessDef").Preload("Starter").First(&instance, id).Error; err != nil {
		response.NotFound(c, "流程实例不存在")
		return
	}

	var tasks []model.Task
	h.db.Where("instance_id = ?", id).
		Preload("Assignee").
		Order("created_at ASC").
		Find(&tasks)

	response.Success(c, gin.H{
		"instance": instance,
		"tasks":    tasks,
	})
}

// ==================== 任务管理 ====================

// GetPendingTasks 获取当前用户的待办任务
// @Summary      获取待办任务
// @Description  获取当前用户的待处理流程任务列表
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/tasks/pending [get]
func (h *Handler) GetPendingTasks(c *gin.Context) {
	userID := utils.GetUserID(c)

	var tasks []model.Task
	h.db.Where("assignee_id = ? AND status = 0", userID).
		Preload("Instance").
		Preload("Instance.ProcessDef").
		Preload("Assignee").
		Order("created_at DESC").
		Find(&tasks)

	response.Success(c, tasks)
}

// ApproveTask 审批通过任务
// @Summary      审批通过任务
// @Description  审批通过指定的流程任务
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        id   path uint          true "任务ID"
// @Param        body body TaskActionReq true "审批请求"
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/tasks/{id}/approve [post]
func (h *Handler) ApproveTask(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	var req TaskActionReq
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	userID := utils.GetUserID(c)

	if err := h.engine.ApproveTask(uint(id), userID, req.Comment); err != nil {
		response.InternalError(c, err.Error())
		return
	}

	// 审批完成后发送通知
	h.sendAppointmentNotification(uint(id))
	h.sendDingTalkAfterApproval(uint(id), req.Comment)

	response.SuccessWithMessage(c, "审批通过", nil)
}

// RejectTask 审批拒绝任务
// @Summary      审批拒绝任务
// @Description  拒绝指定的流程任务
// @Tags         工作流
// @Accept       json
// @Produce      json
// @Security     BearerAuth
// @Param        id   path uint          true "任务ID"
// @Param        body body TaskActionReq true "拒绝请求"
// @Success      200  {object}  response.Response  "success"
// @Router       /api/v1/workflow/tasks/{id}/reject [post]
func (h *Handler) RejectTask(c *gin.Context) {
	id, err := strconv.ParseUint(c.Param("id"), 10, 64)
	if err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	var req TaskActionReq
	if err := c.ShouldBindJSON(&req); err != nil {
		response.BadRequest(c, "参数错误")
		return
	}

	userID := utils.GetUserID(c)

	if err := h.engine.RejectTask(uint(id), userID, req.Comment); err != nil {
		response.InternalError(c, err.Error())
		return
	}

	// 拒绝后发送通知
	h.sendAppointmentNotification(uint(id))
	h.sendDingTalkAfterRejection(uint(id), req.Comment)

	response.SuccessWithMessage(c, "已拒绝", nil)
}

// sendAppointmentNotification 审批结束后发送微信通知给申请人
func (h *Handler) sendAppointmentNotification(taskID uint) {
	var task model.Task
	if err := h.db.Preload("Instance").First(&task, taskID).Error; err != nil {
		return
	}
	if task.Instance == nil || task.Instance.BusinessType != "appointment" {
		return
	}

	go func() {
		var appointment model.Appointment
		if err := h.db.First(&appointment, task.Instance.BusinessID).Error; err != nil {
			return
		}
		// 只发送已通过或已拒绝的通知
		if appointment.Status != 1 && appointment.Status != 2 {
			return
		}

		var creatorUser model.User
		if err := h.db.First(&creatorUser, appointment.CreatorUserID).Error; err != nil || creatorUser.Openid == "" {
			return
		}

		resultText := "已通过"
		if appointment.Status == 2 {
			resultText = "已拒绝"
		}

		// 解析 JSON 字段
		var employeeInfo map[string]interface{}
		json.Unmarshal([]byte(appointment.EmployeeInfo), &employeeInfo)
		var visitorInfo map[string]interface{}
		json.Unmarshal([]byte(appointment.VisitorInfo), &visitorInfo)
		company, _ := visitorInfo["company"].(string)
		employeeName, _ := employeeInfo["name"].(string)

		var areasInfo []string
		json.Unmarshal([]byte(appointment.AreasInfo), &areasInfo)
		areaText := strings.Join(areasInfo, "、")

		// 格式化时间（微信 thing 类型字段限 20 字）
		timeStr := ""
		if !appointment.VisitStartTime.IsZero() {
			loc, _ := time.LoadLocation("Asia/Shanghai")
			timeStr = appointment.VisitStartTime.In(loc).Format("01-02 15:04") + "-" + appointment.VisitEndTime.In(loc).Format("15:04")
		}

		// TMPL_RESULT: 访客申请结果通知（thing 字段限 20 字）
		trunc := func(s string) string {
			runes := []rune(s)
			if len(runes) > 20 {
				return string(runes[:20])
			}
			return s
		}
		tmplID := templates.TMPL_RESULT
		if h.wxSend != nil {
			h.wxSend(creatorUser.Openid, tmplID, map[string]string{
				"thing1": trunc(resultText),
				"thing2": trunc(company),
				"thing3": trunc(timeStr),
				"thing8": trunc(employeeName),
				"thing9": trunc(areaText),
			}, fmt.Sprintf("/subpackages/appointment/appointment-detail?id=%d", appointment.ID))
		}
	}()
}

// sendDingTalkAfterApproval 审批通过后发送钉钉消息
func (h *Handler) sendDingTalkAfterApproval(taskID uint, comment string) {
	if h.dingTalk == nil {
		return
	}

	var task model.Task
	if err := h.db.Preload("Instance").First(&task, taskID).Error; err != nil {
		return
	}
	if task.Instance == nil || task.Instance.BusinessType != "appointment" || task.Instance.Status != 0 {
		return
	}

	logrus.WithFields(logrus.Fields{
		"task_id":     taskID,
		"instance_id": task.InstanceID,
	}).Info("钉钉：审批通过，开始发送通知")

	go func() {
		// 获取审批人信息
		var approverUser model.User
		if task.AssigneeID == nil {
			return
		}
		if err := h.db.First(&approverUser, *task.AssigneeID).Error; err != nil {
			logrus.WithError(err).WithField("task_id", taskID).Warn("钉钉：查询审批人信息失败")
			return
		}

		// 获取预约信息
		var appointment model.Appointment
		if err := h.db.First(&appointment, task.Instance.BusinessID).Error; err != nil {
			return
		}

		var visitorInfo struct {
			Name    string `json:"name"`
			Company string `json:"company"`
		}
		json.Unmarshal([]byte(appointment.VisitorInfo), &visitorInfo)
		visitTime := ""
		if !appointment.VisitStartTime.IsZero() {
			visitTime = dingtalk.FormatCSTTime(appointment.VisitStartTime, appointment.VisitEndTime)
		}

		// 1. 通知被取消的同节点审批人（同一节点非会签模式，其他人审批后当前节点其他人被取消）
		var cancelledTasks []model.Task
		if err := h.db.Where("instance_id = ? AND node_id = ? AND status = 3 AND id != ?",
			task.InstanceID, task.NodeID, task.ID).Find(&cancelledTasks).Error; err == nil && len(cancelledTasks) > 0 {
			var userIDs []string
			for _, ct := range cancelledTasks {
				if ct.AssigneeID != nil {
					var ud model.UserDepartment
					if err := h.db.Where("user_id = ?", *ct.AssigneeID).First(&ud).Error; err == nil && ud.DingTalkUserID != "" {
						userIDs = append(userIDs, ud.DingTalkUserID)
					} else if err != nil {
						logrus.WithError(err).WithField("user_id", *ct.AssigneeID).Warn("钉钉：查询同节点取消人 UserDepartment 失败")
					} else {
						logrus.WithField("user_id", *ct.AssigneeID).Warn("钉钉：同节点取消人 DingTalkUserID 为空")
					}
				}
			}
			if len(userIDs) > 0 {
				title, markdown := dingtalk.BuildSameNodeCancelledMsg(approverUser.RealName, comment, visitTime)
				logrus.WithFields(logrus.Fields{
					"user_ids": userIDs,
					"title":    title,
				}).Info("钉钉：发送同节点取消通知")
				if err := h.dingTalk.BatchSendRobotMessage(userIDs, title, markdown); err != nil {
					logrus.WithError(err).Error("钉钉发送同节点取消通知失败")
				}
			} else {
				logrus.WithField("cancelled_count", len(cancelledTasks)).Info("钉钉：同节点已取消任务无有效钉钉ID")
			}
		} else {
			logrus.WithField("has_cancelled", len(cancelledTasks) > 0).Info("钉钉：无同节点取消任务")
		}

		// 2. 通知下一个节点审批人
		var pendingTasks []model.Task
		if err := h.db.Where("instance_id = ? AND status = 0", task.InstanceID).Find(&pendingTasks).Error; err == nil && len(pendingTasks) > 0 {
			var userIDs []string
			for _, pt := range pendingTasks {
				if pt.AssigneeID != nil {
					var ud model.UserDepartment
					if err := h.db.Where("user_id = ?", *pt.AssigneeID).First(&ud).Error; err == nil && ud.DingTalkUserID != "" {
						userIDs = append(userIDs, ud.DingTalkUserID)
					} else if err != nil {
						logrus.WithError(err).WithField("user_id", *pt.AssigneeID).Warn("钉钉：查询下一节点审批人 UserDepartment 失败")
					} else {
						logrus.WithField("user_id", *pt.AssigneeID).Warn("钉钉：下一节点审批人 DingTalkUserID 为空")
					}
				}
			}
			if len(userIDs) > 0 {
				msg := &dingtalk.AppointmentResultMessage{
					ApproverName:  approverUser.RealName,
					Action:        "通过",
					Comment:       comment,
					AppointmentID: appointment.ID,
					VisitTime:     visitTime,
					VisitorName:   visitorInfo.Name,
				}
				title, markdown := dingtalk.BuildApproveNotificationMsg(msg)
				logrus.WithFields(logrus.Fields{
					"user_ids": userIDs,
					"title":    title,
				}).Info("钉钉：发送下一节点审批人通知")
				if err := h.dingTalk.BatchSendRobotMessage(userIDs, title, markdown); err != nil {
					logrus.WithError(err).Error("钉钉发送下一节点通知失败")
				}
			} else {
				logrus.WithField("pending_count", len(pendingTasks)).Info("钉钉：下一节点无有效钉钉ID的审批人")
			}
		} else {
			logrus.WithField("has_pending", len(pendingTasks) > 0).Info("钉钉：无下一节点待审批任务")
		}
	}()
}

// sendDingTalkAfterRejection 审批拒绝后发送钉钉消息
func (h *Handler) sendDingTalkAfterRejection(taskID uint, comment string) {
	if h.dingTalk == nil {
		return
	}

	var task model.Task
	if err := h.db.Preload("Instance").First(&task, taskID).Error; err != nil {
		return
	}
	if task.Instance == nil || task.Instance.BusinessType != "appointment" {
		return
	}

	logrus.WithFields(logrus.Fields{
		"task_id":     taskID,
		"instance_id": task.InstanceID,
	}).Info("钉钉：审批拒绝，开始发送通知")

	go func() {
		// 获取拒绝人信息
		var rejector model.User
		if task.AssigneeID == nil {
			return
		}
		if err := h.db.First(&rejector, *task.AssigneeID).Error; err != nil {
			logrus.WithError(err).WithField("task_id", taskID).Warn("钉钉：查询拒绝人信息失败")
			return
		}

		// 获取预约信息
		var appointment model.Appointment
		if err := h.db.First(&appointment, task.Instance.BusinessID).Error; err != nil {
			return
		}

		var visitorInfo struct {
			Name    string `json:"name"`
			Company string `json:"company"`
		}
		json.Unmarshal([]byte(appointment.VisitorInfo), &visitorInfo)
		visitTime := ""
		if !appointment.VisitStartTime.IsZero() {
			visitTime = dingtalk.FormatCSTTime(appointment.VisitStartTime, appointment.VisitEndTime)
		}

		// 查找本实例中其他待审批任务，通知其审批人流程已终止
		var otherPendingTasks []model.Task
		if err := h.db.Where("instance_id = ? AND status = 0 AND id != ?", task.InstanceID, task.ID).Find(&otherPendingTasks).Error; err != nil {
			return
		}

		var userIDs []string
		for _, pt := range otherPendingTasks {
			if pt.AssigneeID != nil {
				var ud model.UserDepartment
				if err := h.db.Where("user_id = ?", *pt.AssigneeID).First(&ud).Error; err == nil && ud.DingTalkUserID != "" {
					userIDs = append(userIDs, ud.DingTalkUserID)
				} else if err != nil {
					logrus.WithError(err).WithField("user_id", *pt.AssigneeID).Warn("钉钉：查询其他待审批人 UserDepartment 失败")
				} else {
					logrus.WithField("user_id", *pt.AssigneeID).Warn("钉钉：其他待审批人 DingTalkUserID 为空")
				}
			}
		}

		if len(userIDs) > 0 {
			msg := &dingtalk.AppointmentResultMessage{
				ApproverName:  rejector.RealName,
				Action:        "拒绝",
				Comment:       comment,
				AppointmentID: appointment.ID,
				VisitTime:     visitTime,
				VisitorName:   visitorInfo.Name,
			}
			title, markdown := dingtalk.BuildRejectNotificationMsg(msg)
			logrus.WithFields(logrus.Fields{
				"user_ids": userIDs,
				"title":    title,
			}).Info("钉钉：发送拒绝通知给其他待审批人")
			if err := h.dingTalk.BatchSendRobotMessage(userIDs, title, markdown); err != nil {
				logrus.WithError(err).Error("钉钉发送拒绝通知失败")
			}
		} else {
			logrus.WithField("other_pending_count", len(otherPendingTasks)).Info("钉钉：拒绝后无其他待审批人需通知")
		}
	}()
}
