package com.ruoyi.ibs.task.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.Page;
import com.ruoyi.common.core.page.TableDataPageInfo;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.ibs.task.domain.dto.AlterForwardRequest;
import com.ruoyi.ibs.task.domain.dto.ForwardTarget;
import com.ruoyi.ibs.task.domain.dto.WorkRecordDTO;
import com.ruoyi.ibs.task.domain.entity.AlterAssignHistory;
import com.ruoyi.ibs.task.domain.entity.AlterConfig;
import com.ruoyi.ibs.task.domain.entity.WorkRecord;
import com.ruoyi.ibs.task.domain.vo.*;
import com.ruoyi.ibs.task.mapper.AlterAssignHistoryMapper;
import com.ruoyi.ibs.task.mapper.WorkRecordMapper;
import com.ruoyi.ibs.task.service.WorkRecordService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.domain.SysPost;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 工作清单记录Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-10-11
 */
@Slf4j
@Service
public class WorkRecordServiceImpl implements WorkRecordService {

    private final static String alterTypesRedisKey = "work:record:alter:types";
    private static final String ROLE_MANAGER = "manager";
    private static final String ROLE_BRANCH = "branch";
    private static final String ROLE_OUTLET = "outlet";
    private static final String TARGET_TYPE_DEPT = "dept";
    private static final String TARGET_TYPE_USER = "user";
    private static final Set<String> FORWARD_ALTER_TYPES = new HashSet<>(Arrays.asList(
            "个人资产客户定期存款",
            "个人资产客户封闭式理财"
    ));

    @Autowired
    private WorkRecordMapper workRecordMapper;

    @Autowired
    private AlterAssignHistoryMapper alterAssignHistoryMapper;

    @Autowired
    private ISysPostService sysPostService;

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private RedisCache redisCache;

    /**
     * 查询我的工作清单
     * 
     * @param workRecordDTO 工作清单记录
     * @return 工作清单记录
     */
    @Override
    public List<WorkRecordVO> getWorkRecordList(WorkRecordDTO workRecordDTO) {
        String username = SecurityUtils.getUsername();
        return workRecordMapper.selectWorkRecordList(workRecordDTO, username);
    }

    /**
     * 查询权限内所有工作清单(仅限管理员)
     * 1、根据当前登录者觉得获取权限内的部门列表
     * 2、查询work_record表里在这些部门列表里的用户
     *
     * @param workRecordDTO 工作清单记录
     * @return 工作清单记录
     */
    @Override
    public TableDataPageInfo<WorkRecordVO> getAllWorkRecordList(WorkRecordDTO workRecordDTO) {
        List<Long> postIds = getPostIdsByRole();
        //开启分页 避开上一个sql
        Page<Object> page = PageUtils.startPage();
        if (SecurityUtils.userRole().equals("manager")){
            List<WorkRecordVO> list = workRecordMapper.selectAllWorkRecordList(workRecordDTO, null, SecurityUtils.getUsername());
            return PageUtils.getDataTable(list, page);
        }else {
            if (postIds.isEmpty()){
                return PageUtils.getDataTable(new ArrayList<>(), page);
            }
            List<WorkRecordVO> list = workRecordMapper.selectAllWorkRecordList(workRecordDTO, postIds, null);
            return PageUtils.getDataTable(list, page);
        }
    }

    /**
     * 修改工作清单记录（只能修改状态和备注）
     * 
     * @param workRecordList 工作清单记录
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchSubmitWorkRecord(List<WorkRecord> workRecordList) {
        if (workRecordList.isEmpty()){
            return 0;
        }
        return workRecordMapper.batchSubmitWorkRecord(workRecordList);
    }

    /**
     * 查询权限内用户工作清单完成情况(仅限管理员)
     *
     * 1、查询当前登录用户权限范围内所有post_ids
     * 2、根据post_ids查询work_record表的所有集合，按照用户分组
     * 3、评估每个用户完成情况
     *
     * @param workRecordDTO 工作清单记录主键
     * @return 工作清单记录
     */
    @Override
    public TableDataPageInfo<WorkCompleteVO> getCompleteStatus(WorkRecordDTO workRecordDTO) {
        List<Long> postIds = getPostIdsByRole();
        //开启分页 避开上一个sql
        Page<Object> page = PageUtils.startPage();
        if (postIds.isEmpty()){
            return PageUtils.getDataTable(new ArrayList<>(), page);
        }
        List<WorkCompleteVO> voList= workRecordMapper.selectCompleteStatus(workRecordDTO, postIds);
        //计算排名
        int rankNum = (page.getPageNum() - 1) * page.getPageSize() + 1;
        if (voList != null && !voList.isEmpty()){
            IntStream.range(0, voList.size()).forEach(i -> voList.get(i).setRankNum(rankNum + i));
        }
        return PageUtils.getDataTable(voList, page);
    }

    /**
     * 获取我的预警信息
     *
     * @param alterType 预警类型
     * @return 预警信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<AlterVO> getAlterList(String status, String alterType) {
        String username = SecurityUtils.getUsername();
        List<AlterVO> alterVOS = workRecordMapper.selectAlterList(username, status, alterType);
        fillAlterExtFields(alterVOS);
        return alterVOS;
    }

    /**
     * 获取权限内所有预警信息(仅限管理员)
     *
     * 1、根据登录者角色查询权限内部门ids
     * 2、根据部门ids查询work_record表里所有该部门下的所有用户对应的预警信息
     *
     * @param alterType 预警类型
     * @return 预警信息
     */
    @Override
    public List<AlterVO> getAllAlterList(String status, String alterType, String forwardFlag) {
        List<AlterVO> alterVOS = workRecordMapper.selectAllAlterList(
                String.valueOf(SecurityUtils.getDeptId()),
                SecurityUtils.userRole(),
                status,
                alterType,
                SecurityUtils.getUsername(),
                forwardFlag
        );
        fillAlterExtFields(alterVOS);
        return alterVOS;
    }

    /**
     * 查询转发弹窗所需元数据。
     * 单选时返回手动选项并附带历史推荐；多选时根据是否存在历史记录决定走手动分配还是历史推荐模式。
     */
    @Override
    public AlterForwardMetaVO getAlterForwardMeta(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new ServiceException("请选择需要转发的预警");
        }
        AlterForwardMetaVO metaVO = new AlterForwardMetaVO();
        String role = requireForwardRole();
        Long currentDeptId = SecurityUtils.getDeptId();
        String currentUser = SecurityUtils.getUsername();
        List<WorkRecord> workRecords = workRecordMapper.selectBatchIds(ids);
        if (workRecords == null || workRecords.size() != ids.size()) {
            throw new ServiceException("存在预警记录已不存在，请刷新后重试");
        }
        workRecords.forEach(item -> validateRecordBeforeForward(item, role, currentUser, currentDeptId));
        if (ids.size() > 1) {
            boolean hasAnyHistory = workRecords.stream()
                    .map(item -> getHistoryRecommend(item.getCustId(), currentDeptId, role))
                    .anyMatch(Objects::nonNull);
            metaVO.setHasHistoryRecommend(hasAnyHistory);
            metaVO.setHistoryOnly(hasAnyHistory);
            if (!hasAnyHistory) {
                fillManualOptions(metaVO, role, currentDeptId);
            }
            return metaVO;
        }
        WorkRecord workRecord = workRecords.get(0);
        fillManualOptions(metaVO, role, currentDeptId);
        fillHistoryRecommend(metaVO, workRecord.getCustId(), currentDeptId, role);
        return metaVO;
    }

    /**
     * 执行预警转发。
     * 支持手动分配和按历史推荐分配两种模式，并分别统计成功和失败数量。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AlterForwardResultVO forwardAlter(AlterForwardRequest request) {
        String role = requireForwardRole();
        String currentUser = SecurityUtils.getUsername();
        Long currentDeptId = SecurityUtils.getDeptId();
        AlterForwardResultVO result = new AlterForwardResultVO();
        boolean useHistory = Boolean.TRUE.equals(request.getUseHistory());
        ForwardTarget manualTarget = useHistory ? null : resolveManualTarget(request, role, currentDeptId);

        List<WorkRecord> workRecords = workRecordMapper.selectBatchIds(request.getIds());
        if (workRecords == null || workRecords.size() != request.getIds().size()) {
            throw new ServiceException("存在预警记录已不存在，请刷新后重试");
        }

        for (WorkRecord workRecord : workRecords) {
            validateRecordBeforeForward(workRecord, role, currentUser, currentDeptId);
            AlterAssignHistory history = useHistory ? getHistoryRecommend(workRecord.getCustId(), currentDeptId, role) : null;
            ForwardTarget target = useHistory ? resolveHistoryTarget(history, role, currentDeptId) : manualTarget;
            if (target == null) {
                result.setFailCount(result.getFailCount() + 1);
                continue;
            }
            int row = doForward(workRecord.getId(), currentUser, currentDeptId, role, target);
            if (row <= 0) {
                result.setFailCount(result.getFailCount() + 1);
                continue;
            }
            result.setSuccessCount(result.getSuccessCount() + row);
            if (useHistory) {
                if (history != null) {
                    saveAssignHistoryByHistory(workRecord, history, role, currentDeptId);
                }
            } else {
                saveAssignHistory(workRecord, manualTarget, role, currentDeptId);
            }
        }
        return result;
    }

    /**
     * 定时任务生成工作清单
     *
     * 1、根据频率类型计算时间范围
     * 2、查询模板表里当前频率类型处于启用状态下的工作清单（联表查用户信息等）
     * 3、插入工作清单记录表
     *
     * @param frequencyType 频率类型
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int generateWorkRecordScheduled(String frequencyType) {
        log.info("=====开始执行生成工作清单定时任务=====,频率类型为: " + frequencyType);
        //计算时间范围
        LocalDate today = LocalDate.now();
        Date startTime = calculateStartTime(frequencyType, today);
        Date endTime = calculateEndTime(frequencyType, today);
        log.info("时间范围: {} 至 {}", startTime, endTime);
        List<WorkRecord> recordsToGenerate = workRecordMapper.selectRecordsToGenerate(frequencyType, startTime, endTime);
        if (recordsToGenerate.isEmpty()){
            log.info("没有需要生成的记录");
            return 0;
        }
        log.info("需要生成的记录数量: {}", recordsToGenerate.size());
        int insertCount = workRecordMapper.batchInsertWorkRecord(recordsToGenerate);
        log.info("=====生成工作清单定时任务执行成功=====, 生成工作清单记录数量: {}", insertCount);
        return insertCount;
    }

    /**
     * 定时判断工作清单是否逾期，每日凌晨一点判断一次
     *
     * 1、获取当前时间
     * 2、查询表里当前时间在start_time和end_time之间，并且is_overdue为0的记录，修改is_overdue为1
     *
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int setOverdue(){
        //获取当前时间
        LocalDateTime now = LocalDateTime.now();
        log.info("=====开始执行设置逾期工作清单定时任务=====,当前时间为: " + now);
        //查询工作清单记录
        return workRecordMapper.updateOverdueRecord(now);
    }

    /**
     * 获取预警配置信息
     * @return
     */
    @Override
    public List<AlterConfigVO> getAlterConfigList(String alterType){
        return workRecordMapper.selectAlterConfigList(alterType);
    }

    @Override
    public int updateAlterConfig(AlterConfig alterConfig){
        alterConfig.setUpdateBy(SecurityUtils.getUsername());
        alterConfig.setUpdateTime(new Date());
        return workRecordMapper.updateAlterConfig(alterConfig);
    }

    @Override
    public int updateReadTime(Long id) {
        return workRecordMapper.updateReadTime(id, SecurityUtils.getUsername());
    }

    @Override
    public AlterCountVO getAlterCount(Date reportTime) {
        AlterCountVO alterCountVO = workRecordMapper.selectAlterCount(reportTime, SecurityUtils.userRole(), String.valueOf(SecurityUtils.getDeptId()));
        // 计算完成率
        if (alterCountVO.getAlterCount() > 0) {
            BigDecimal completeRate = BigDecimal.valueOf(alterCountVO.getCompleteCount())
                    .multiply(BigDecimal.valueOf(100))
                    .divide(BigDecimal.valueOf(alterCountVO.getAlterCount()), 2, RoundingMode.HALF_UP);
            alterCountVO.setCompleteRate(completeRate);
        } else {
            alterCountVO.setCompleteRate(BigDecimal.ZERO);
        }
        return alterCountVO;
    }

    @Override
    public List<String> getAlterTypes() {
        String headId = SecurityUtils.getHeadId();
        String cacheKey = alterTypesRedisKey + ":" + headId;
        List<String> cachedTypes = redisCache.getCacheObject(cacheKey);
        if (cachedTypes != null) {
            return cachedTypes;
        }
        List<String> types = workRecordMapper.selectAlterTypes(headId);
        redisCache.setCacheObjectToEndDay(cacheKey, types);
        return types;
    }

    /**
     * 获取当前登录用户权限范围内所有post_ids
     * @return
     */
    private List<Long> getPostIdsByRole(){
        List<SysPost> sysPosts = sysPostService.selectPostList(new SysPost());
        if (sysPosts == null || sysPosts.isEmpty()){
            return new ArrayList<>();
        }
        return sysPosts.stream()
                .map(SysPost::getPostId)
                .collect(Collectors.toList());
    }

    /**
     * 计算工作清单开始时间
     * @param frequencyType
     * @param date
     * @return
     */
    private Date calculateStartTime(String frequencyType, LocalDate date){
        LocalDateTime startTime;
        switch (frequencyType){
            case "0":
                startTime = LocalDateTime.of(date, LocalTime.MIN);
                break;
            case "1":
                startTime= LocalDateTime.of(date.with(DayOfWeek.MONDAY), LocalTime.MIN);
                break;
            case "2":
                startTime = LocalDateTime.of(date.with(TemporalAdjusters.firstDayOfMonth()), LocalTime.MIN);
                break;
            case "3":
                int quarter = (date.getMonthValue() - 1) / 3;
                int firstMonthOfQuarter = quarter * 3 + 1;
                startTime = LocalDateTime.of(LocalDate.of(date.getYear(), firstMonthOfQuarter,1), LocalTime.MIN);
                break;
            case "4":
                startTime = LocalDateTime.of(LocalDate.of(date.getYear(), 1, 1), LocalTime.MIN);
                break;
            default:
                throw new IllegalArgumentException("不支持的频率类型: " + frequencyType);
        }
        return java.sql.Timestamp.valueOf(startTime);
    }

    /**
     * 计算工作清单结束时间
     * @param frequencyType
     * @param date
     * @return
     */
    private Date calculateEndTime(String frequencyType, LocalDate date){
        LocalDateTime endTime;
        switch (frequencyType){
            case "0":
                endTime = LocalDateTime.of(date, LocalTime.MAX);
                break;
            case "1":
                endTime = LocalDateTime.of(date.with(DayOfWeek.SUNDAY), LocalTime.MAX);
                break;
            case "2":
                endTime = LocalDateTime.of(date.with(TemporalAdjusters.lastDayOfMonth()), LocalTime.MAX);
                break;
            case "3":
                int quarter = (date.getMonthValue() - 1) / 3;
                int lastMonthOfQuarter = quarter * 3 + 3;
                LocalDate lastDayOfQuarter = LocalDate.of(date.getYear(), lastMonthOfQuarter, 1).with(TemporalAdjusters.lastDayOfMonth());
                endTime = LocalDateTime.of(lastDayOfQuarter, LocalTime.MAX);
                break;
            case "4":
                endTime= LocalDateTime.of(LocalDate.of(date.getYear(), 12, 31), LocalTime.MAX);
                break;
            default:
                throw new IllegalArgumentException("不支持的频率类型: " + frequencyType);
        }
        return java.sql.Timestamp.valueOf(endTime);
    }

    private void fillAlterExtFields(List<AlterVO> alterVOS) {
        if (alterVOS == null || alterVOS.isEmpty()) {
            return;
        }
        String role = SecurityUtils.userRole();
        Long currentDeptId = SecurityUtils.getDeptId();
        String currentUser = SecurityUtils.getUsername();
        alterVOS.forEach(alterVO -> {
            alterVO.setForwardFlag(parseForwardFlag(alterVO.getAlterDetail()));
            alterVO.setAlterDetail(stripForwardPrefix(alterVO.getAlterDetail()));
            alterVO.setUserInfo(buildUserInfo(alterVO.getUserName(), alterVO.getNickName()));
            alterVO.setCanForward(canForward(alterVO, role, currentDeptId, currentUser));
        });
    }

    private String buildUserInfo(String userName, String nickName) {
        if (StringUtils.isNotEmpty(userName) && StringUtils.isNotEmpty(nickName)) {
            return nickName + "-" + userName;
        }
        if (StringUtils.isNotEmpty(userName)) {
            return userName;
        }
        if (StringUtils.isNotEmpty(nickName)) {
            return nickName;
        }
        return "";
    }

    private String parseForwardFlag(String alterDetail) {
        if (StringUtils.isEmpty(alterDetail)) {
            return "";
        }
        if (alterDetail.startsWith("[FORWARD=1]")) {
            return "1";
        }
        if (alterDetail.startsWith("[FORWARD=0]")) {
            return "0";
        }
        return "";
    }

    private String stripForwardPrefix(String alterDetail) {
        if (StringUtils.isEmpty(alterDetail)) {
            return alterDetail;
        }
        if (alterDetail.startsWith("[FORWARD=1] ")) {
            return alterDetail.substring(12);
        }
        if (alterDetail.startsWith("[FORWARD=0] ")) {
            return alterDetail.substring(12);
        }
        if (alterDetail.startsWith("[FORWARD=1]") || alterDetail.startsWith("[FORWARD=0]")) {
            return alterDetail.substring(11);
        }
        return alterDetail;
    }

    private Boolean canForward(AlterVO alterVO, String role, Long currentDeptId, String currentUser) {
        if (!FORWARD_ALTER_TYPES.contains(alterVO.getAlterType())) {
            return false;
        }
        if (!"1".equals(alterVO.getForwardFlag())) {
            return false;
        }
        if ("2".equals(alterVO.getStatus())) {
            return false;
        }
        if (ROLE_BRANCH.equals(role)) {
            return StringUtils.equals(currentUser, alterVO.getUserName()) && alterVO.getDeptId() == null;
        }
        if (ROLE_OUTLET.equals(role)) {
            return alterVO.getDeptId() != null && alterVO.getDeptId().equals(currentDeptId) && StringUtils.isEmpty(alterVO.getUserName());
        }
        return false;
    }

    /**
     * 校验当前登录角色是否具备预警转发能力，并返回角色标识。
     */
    private String requireForwardRole() {
        String role = SecurityUtils.userRole();
        if (!ROLE_BRANCH.equals(role) && !ROLE_OUTLET.equals(role)) {
            throw new ServiceException("当前角色不支持转发预警");
        }
        return role;
    }

    /**
     * 校验预警记录当前是否仍处于登录人可转发范围内，防止页面停留期间数据状态已变化。
     */
    private void validateRecordBeforeForward(WorkRecord workRecord, String role, String currentUser, Long currentDeptId) {
        if (workRecord == null || workRecord.getId() == null) {
            throw new ServiceException("预警记录不存在");
        }
        if (!Integer.valueOf(1).equals(workRecord.getIsAlter())) {
            throw new ServiceException("当前记录不是预警信息");
        }
        if (!FORWARD_ALTER_TYPES.contains(workRecord.getAlterType())) {
            throw new ServiceException("当前预警类型不支持转发");
        }
        if (!"1".equals(parseForwardFlag(workRecord.getAlterDetail()))) {
            throw new ServiceException("当前预警已有管户，无需转发");
        }
        if ("2".equals(workRecord.getStatus())) {
            throw new ServiceException("当前预警已完成，不能转发");
        }
        if (ROLE_BRANCH.equals(role)) {
            if (!StringUtils.equals(currentUser, workRecord.getUserName()) || workRecord.getDeptId() != null) {
                throw new ServiceException("当前预警已不在您的待转发范围内");
            }
            return;
        }
        if (ROLE_OUTLET.equals(role)) {
            if (workRecord.getDeptId() == null || !workRecord.getDeptId().equals(currentDeptId) || StringUtils.isNotEmpty(workRecord.getUserName())) {
                throw new ServiceException("当前预警已不在本网点待转发范围内");
            }
            return;
        }
        throw new ServiceException("当前角色不支持转发预警");
    }

    /**
     * 解析手动转发目标，并顺带完成目标权限范围校验。
     */
    private ForwardTarget resolveManualTarget(AlterForwardRequest request, String role, Long currentDeptId) {
        if (TARGET_TYPE_DEPT.equals(request.getTargetType())) {
            if (request.getDeptId() == null) {
                throw new ServiceException("请选择转发网点");
            }
            if (!ROLE_BRANCH.equals(role)) {
                throw new ServiceException("网点管理员只能转发给客户经理");
            }
            String deptName = getAllowedDeptName(request.getDeptId(), currentDeptId);
            return new ForwardTarget(TARGET_TYPE_DEPT, request.getDeptId(), null, null, deptName);
        }
        if (!TARGET_TYPE_USER.equals(request.getTargetType()) || StringUtils.isEmpty(request.getUserName())) {
            throw new ServiceException("请选择转发客户经理");
        }
        SysUser user = getAllowedTargetUser(request.getUserName(), role, currentDeptId);
        String targetName = StringUtils.isNotEmpty(user.getNickName()) ? user.getNickName() : user.getUserName();
        return new ForwardTarget(TARGET_TYPE_USER, null, user.getUserName(), user.getNickName(), targetName);
    }

    /**
     * 将历史分配记录转换成可执行的转发目标；若历史目标已失效，则返回空。
     */
    private ForwardTarget resolveHistoryTarget(AlterAssignHistory history, String role, Long currentDeptId) {
        if (history == null) {
            return null;
        }
        if (TARGET_TYPE_DEPT.equals(history.getLastAssignTargetType())) {
            if (history.getLastAssignTargetDeptId() == null) {
                return null;
            }
            String deptName = getAllowedDeptName(history.getLastAssignTargetDeptId(), currentDeptId);
            return new ForwardTarget(TARGET_TYPE_DEPT, history.getLastAssignTargetDeptId(), null, null, deptName);
        }
        if (!TARGET_TYPE_USER.equals(history.getLastAssignTargetType()) || StringUtils.isEmpty(history.getLastAssignTargetUser())) {
            return null;
        }
        try {
            SysUser user = getAllowedTargetUser(history.getLastAssignTargetUser(), role, currentDeptId);
            String targetName = StringUtils.isNotEmpty(user.getNickName()) ? user.getNickName() : user.getUserName();
            return new ForwardTarget(TARGET_TYPE_USER, null, user.getUserName(), user.getNickName(), targetName);
        } catch (ServiceException ex) {
            return null;
        }
    }

    /**
     * 按目标类型执行真正的转发落库更新。
     */
    private int doForward(Long workRecordId, String currentUser, Long currentDeptId, String role, ForwardTarget target) {
        if (TARGET_TYPE_DEPT.equals(target.getTargetType())) {
            return workRecordMapper.updateAlterForwardToDept(workRecordId, currentUser, target.getDeptId(), currentUser);
        }
        if (ROLE_BRANCH.equals(role)) {
            return workRecordMapper.updateAlterForwardToUserByBranch(
                    workRecordId, currentUser, target.getUserName(), target.getNickName(), currentUser
            );
        }
        return workRecordMapper.updateAlterForwardToUserByOutlet(
                workRecordId, currentDeptId, target.getUserName(), target.getNickName(), currentUser
        );
    }

    /**
     * 校验目标网点是否在当前支行管理员的可转发范围内，并返回网点名称。
     */
    private String getAllowedDeptName(Long targetDeptId, Long currentDeptId) {
        List<AlterAssignTargetVO> deptOptions = workRecordMapper.selectForwardDeptTargets(currentDeptId);
        return deptOptions.stream()
                .filter(item -> String.valueOf(targetDeptId).equals(item.getTargetCode()))
                .map(AlterAssignTargetVO::getTargetName)
                .findFirst()
                .orElseThrow(() -> new ServiceException("所选网点不在当前支行可转发范围内"));
    }

    /**
     * 校验目标客户经理是否在当前管理员可转发范围内，并返回用户信息。
     */
    private SysUser getAllowedTargetUser(String targetUserName, String role, Long currentDeptId) {
        List<AlterAssignTargetVO> userOptions = workRecordMapper.selectForwardUserTargets(currentDeptId, ROLE_MANAGER);
        boolean matched = userOptions.stream().anyMatch(item -> StringUtils.equals(targetUserName, item.getTargetCode()));
        if (!matched) {
            if (ROLE_BRANCH.equals(role)) {
                throw new ServiceException("所选客户经理不在当前支行可转发范围内");
            }
            throw new ServiceException("所选客户经理不在当前网点可转发范围内");
        }
        SysUser user = sysUserService.selectUserByUserName(targetUserName);
        if (user == null || StringUtils.isEmpty(user.getUserName())) {
            throw new ServiceException("转发目标客户经理不存在");
        }
        return user;
    }

    /**
     * 填充手动分配弹窗可选项；支行管理员可选网点和客户经理，网点管理员仅可选客户经理。
     */
    private void fillManualOptions(AlterForwardMetaVO metaVO, String role, Long currentDeptId) {
        if (ROLE_BRANCH.equals(role)) {
            metaVO.setDeptOptions(workRecordMapper.selectForwardDeptTargets(currentDeptId));
            metaVO.setUserOptions(workRecordMapper.selectForwardUserTargets(currentDeptId, ROLE_MANAGER));
            return;
        }
        if (ROLE_OUTLET.equals(role)) {
            metaVO.setUserOptions(workRecordMapper.selectForwardUserTargets(currentDeptId, ROLE_MANAGER));
            return;
        }
        throw new ServiceException("当前角色不支持转发预警");
    }

    /**
     * 按客户、当前部门和当前角色查询历史推荐，并回填到前端元数据中。
     */
    private void fillHistoryRecommend(AlterForwardMetaVO metaVO, String custId, Long deptId, String role) {
        AlterAssignHistory history = getHistoryRecommend(custId, deptId, role);
        if (history == null) {
            return;
        }
        metaVO.setHasHistoryRecommend(true);
        metaVO.setRecommendedTargetType(history.getLastAssignTargetType());
        if (TARGET_TYPE_DEPT.equals(history.getLastAssignTargetType())) {
            metaVO.setRecommendedTargetCode(history.getLastAssignTargetDeptId() == null ? "" : String.valueOf(history.getLastAssignTargetDeptId()));
        } else {
            metaVO.setRecommendedTargetCode(history.getLastAssignTargetUser());
        }
        metaVO.setRecommendedTargetName(history.getLastAssignTargetName());
    }

    /**
     * 保存本次手动分配结果；同一客户在同部门、同角色下只维护一条最新历史。
     */
    private void saveAssignHistory(WorkRecord workRecord, ForwardTarget target, String role, Long currentDeptId) {
        AlterAssignHistory history = getHistoryRecommend(workRecord.getCustId(), currentDeptId, role);
        if (history == null) {
            history = new AlterAssignHistory();
            history.setCustId(workRecord.getCustId());
        }
        history.setAlterType(workRecord.getAlterType());
        history.setCustName(workRecord.getCustName());
        history.setDeptId(currentDeptId);
        history.setLastAssignTargetType(target.getTargetType());
        history.setLastAssignTargetDeptId(target.getDeptId());
        history.setLastAssignTargetUser(target.getUserName());
        history.setLastAssignTargetName(target.getTargetName());
        history.setLastAssignByUser(SecurityUtils.getUsername());
        history.setLastAssignByRole(role);
        history.setUpdateTime(new Date());
        if (history.getId() == null) {
            alterAssignHistoryMapper.insert(history);
        } else {
            alterAssignHistoryMapper.updateById(history);
        }
    }

    /**
     * 按历史推荐成功转发后，刷新该客户最新一次分配历史的更新时间和目标信息。
     */
    private void saveAssignHistoryByHistory(WorkRecord workRecord, AlterAssignHistory sourceHistory, String role, Long currentDeptId) {
        ForwardTarget target = new ForwardTarget(
                sourceHistory.getLastAssignTargetType(),
                sourceHistory.getLastAssignTargetDeptId(),
                sourceHistory.getLastAssignTargetUser(),
                null,
                sourceHistory.getLastAssignTargetName()
        );
        saveAssignHistory(workRecord, target, role, currentDeptId);
    }

    /**
     * 获取当前角色在当前部门下，对指定客户的最近一次分配历史。
     */
    private AlterAssignHistory getHistoryRecommend(String custId, Long deptId, String role) {
        return alterAssignHistoryMapper.selectOne(new LambdaQueryWrapper<AlterAssignHistory>()
                .eq(AlterAssignHistory::getCustId, custId)
                .eq(AlterAssignHistory::getDeptId, deptId)
                .eq(AlterAssignHistory::getLastAssignByRole, role)
                .last("limit 1"));
    }

}
