package com.sundot.airport.web.controller.system;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Date;
import java.util.*;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sundot.airport.attendance.domain.portrait.WorkDateStats;
import com.sundot.airport.attendance.domain.portrait.WorkHoursStats;
import com.sundot.airport.check.domain.CheckLargeScreenCommonDto;
import com.sundot.airport.check.domain.CheckLargeScreenCorrectionDto;
import com.sundot.airport.check.domain.CheckLargeScreenCorrectionQueryParamDto;
import com.sundot.airport.common.core.domain.ResetUserPostDto;
import com.sundot.airport.common.core.domain.ResetUserRoleDto;
import com.sundot.airport.common.core.domain.SysLargeScreenWorkingPortraitDto;
import com.sundot.airport.common.dto.SysUserConditionDto;
import com.sundot.airport.common.enums.RoleTypeEnum;
import com.sundot.airport.exam.domain.DailyTask;
import com.sundot.airport.attendance.portrait.AttendanceModuleIndicatorResult;
import com.sundot.airport.check.service.ICheckLargeScreenService;
import com.sundot.airport.common.constant.CacheConstants;
import com.sundot.airport.common.core.domain.BaseLargeScreenQueryParamDto;
import com.sundot.airport.common.core.domain.SysLargeScreenDetailDto;
import com.sundot.airport.common.core.redis.RedisCache;
import com.sundot.airport.common.domain.portrait.IndicatorCalculateParams;
import com.sundot.airport.common.domain.portrait.ModularIndicatorResult;
import com.sundot.airport.common.enums.DeptTypeEnum;
import com.sundot.airport.common.enums.portrait.UserType;
import com.sundot.airport.item.domain.portrait.ItemSeizureModuleIndicatorResult;
import com.sundot.airport.item.domain.portrait.SeizureStats;
import com.sundot.airport.system.domain.SysLargeScreenCooperationDto;
import com.sundot.airport.system.domain.SysLargeScreenCooperationQueryParamDto;
import com.sundot.airport.system.domain.portrait.IndicatorResult;
import com.sundot.airport.system.domain.portrait.QualificationStats;
import com.sundot.airport.system.domain.portrait.WorkExperienceStats;
import com.sundot.airport.system.service.ISysLearningGrowthService;
import com.sundot.airport.system.service.portrait.UserPortraitService;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.sundot.airport.common.annotation.Log;
import com.sundot.airport.common.constant.UserConstants;
import com.sundot.airport.common.core.controller.BaseController;
import com.sundot.airport.common.core.domain.AjaxResult;
import com.sundot.airport.common.core.domain.entity.SysDept;
import com.sundot.airport.common.core.domain.entity.SysRole;
import com.sundot.airport.common.core.domain.entity.SysUser;
import com.sundot.airport.common.core.page.TableDataInfo;
import com.sundot.airport.common.enums.BusinessType;
import com.sundot.airport.common.utils.SecurityUtils;
import com.sundot.airport.common.utils.StringUtils;
import com.sundot.airport.common.utils.poi.ExcelUtil;
import com.sundot.airport.system.service.ISysDeptService;
import com.sundot.airport.system.service.ISysPostService;
import com.sundot.airport.system.service.ISysRoleService;
import com.sundot.airport.system.service.ISysUserService;

/**
 * 用户信息
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/system/user")
public class SysUserController extends BaseController {
    @Autowired
    private ISysUserService userService;

    @Autowired
    private ISysRoleService roleService;

    @Autowired
    private ISysDeptService deptService;

    @Autowired
    private ISysPostService postService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ICheckLargeScreenService checkLargeScreenService;

    @Autowired
    private ISysLearningGrowthService sysLearningGrowthService;

    @Autowired
    private ISysUserService iSysUserService;

    @Autowired
    private UserPortraitService userPortraitService;

    @Autowired
    private com.sundot.airport.exam.mapper.DailyTaskMapper dailyTaskMapper;

    /**
     * 获取用户列表
     */
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/list")
    public TableDataInfo list(SysUser user) {
        startPage();
        List<SysUser> list = userService.selectUserList(user);
        return getDataTable(list);
    }

    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
    @PreAuthorize("@ss.hasPermi('system:user:export')")
    @PostMapping("/export")
    public void export(HttpServletResponse response, SysUser user) {
        List<SysUser> list = userService.selectUserList(user);
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        util.exportExcel(response, list, "用户数据");
    }

    @Log(title = "用户管理", businessType = BusinessType.IMPORT)
    @PreAuthorize("@ss.hasPermi('system:user:import')")
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception {
        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
        List<SysUser> userList = util.importExcel(file.getInputStream(), 1);
        String operName = getUsername();
        String message = userService.importUser(userList, updateSupport, operName);
        return success(message);
    }

    @PostMapping("/importTemplate")
    public void importTemplate(HttpServletResponse response) {
        List<SysDept> deptList = deptService.selectDeptList(new SysDept());
        ExcelUtil<SysUser> util = new ExcelUtil<>(SysUser.class);
        util.exportTemplateWithDeptRef(response, deptList, "用户数据导入模板.xlsx");
    }

    /**
     * 查询用户列表
     */
    @PostMapping("/selectUserListByCondition")
    public AjaxResult selectUserListByCondition(@RequestBody SysUserConditionDto dto) {
        List<SysUser> result = userService.selectUserListByDeptIdAndRoleKeyListAndUserName(dto);
        return success(result);
    }

    /**
     * 能力画像-协同配合
     */
    @Cacheable(
            value = "statistics_data",
            keyGenerator = "statisticsKeyGenerator",
            unless = "!T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isSuccess(#result) ||T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isEmptyData(#result)"
    )
    @GetMapping("/cooperation")
    public AjaxResult cooperation(SysLargeScreenCooperationQueryParamDto dto) {
        SysLargeScreenCooperationDto sysLargeScreenCooperationDto = userService.cooperation(dto);
        return success(sysLargeScreenCooperationDto);
    }

    /**
     * 能力画像-总体概览
     */
    @Cacheable(
            value = "statistics_data",
            keyGenerator = "statisticsKeyGenerator",
            unless = "!T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isSuccess(#result) ||T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isEmptyData(#result)"
    )
    @GetMapping("/population")
    public AjaxResult population(BaseLargeScreenQueryParamDto dto) {
        // 默认查询当前登录用户的数据
        if (ObjectUtil.isNull(dto.getUserId()) && ObjectUtil.isNull(dto.getDeptId())) {
            dto.setUserId(getUserId());
        }
        // 传入的用户角色为部门管理员时，则查询部门数据。其中班组长不做处理，由前端处理
        if (Objects.nonNull(dto.getUserId())) {
            SysUser sysUser = userService.selectUserById(dto.getUserId());
            List<SysRole> roles = sysUser.getRoles();
            if (CollUtil.isNotEmpty(roles)) {
                List<String> roleKeyList = roles.stream().map(SysRole::getRoleKey).collect(Collectors.toList());
                if (roleKeyList.contains(RoleTypeEnum.admin.getCode()) || roleKeyList.contains(RoleTypeEnum.test.getCode()) || roleKeyList.contains(RoleTypeEnum.zhijianke.getCode()) || roleKeyList.contains(RoleTypeEnum.jingli.getCode()) || roleKeyList.contains(RoleTypeEnum.xingzheng.getCode()) || roleKeyList.contains(RoleTypeEnum.kezhang.getCode())) {
                    dto.setUserId(null);
                    dto.setDeptId(sysUser.getDeptId());
                }
            }
        }

        // 返回结果
        SysLargeScreenDetailDto result = new SysLargeScreenDetailDto();
        IndicatorCalculateParams indicatorCalculateParams = this.appendParams(dto);
        if (Objects.nonNull(dto.getDeptId())) {
            SysDept sysDept = deptService.selectDeptById(dto.getDeptId());
            if (StrUtil.equals(DeptTypeEnum.STATION.getCode(), sysDept.getDeptType()) || StrUtil.equals(DeptTypeEnum.BRIGADE.getCode(), sysDept.getDeptType()) || StrUtil.equals(DeptTypeEnum.MANAGER.getCode(), sysDept.getDeptType()) || StrUtil.equals(DeptTypeEnum.TEAMS.getCode(), sysDept.getDeptType())) {
                indicatorCalculateParams.setUserType(StrUtil.equals(DeptTypeEnum.STATION.getCode(), sysDept.getDeptType()) ? UserType.STATION : StrUtil.equals(DeptTypeEnum.BRIGADE.getCode(), sysDept.getDeptType()) ? UserType.BRIGADE : StrUtil.equals(DeptTypeEnum.MANAGER.getCode(), sysDept.getDeptType()) ? UserType.DEPARTMENT : UserType.TEAM);
                List<SysUser> sysUsers = iSysUserService.selectUserListByRoleKeyAndDeptId(Arrays.asList(RoleTypeEnum.banzuzhang.getCode(), RoleTypeEnum.SecurityCheck.getCode()), dto.getDeptId());
                indicatorCalculateParams.setUserIds(sysUsers.stream().map(SysUser::getUserId).collect(Collectors.toList()));
                indicatorCalculateParams.setDeptId(dto.getDeptId());
            }
        } else {
            indicatorCalculateParams.setUserType(UserType.PERSONAL);
            indicatorCalculateParams.setUserId(dto.getUserId());
        }

        // 巡检问题总次数
        result.setCheckCount(checkLargeScreenService.population(dto));
        // 学习成长平均分
        result.setLearningGrowthScore(sysLearningGrowthService.population(dto));
        // 工作风格
        result.setWorkingStyle(userService.getWorkingStyle(dto));
        // 主观印象
        result.setSubjectiveImpression(userService.getSubjectiveImpression(dto));
        // 测试平均分（抽问抽答）
        result.setTestScore(calculatePopulationTestScore(dto));

        //工作产出(有效查获数量)
        this.avgSeizureCount(indicatorCalculateParams, result);
        // 资质等级
        this.qualificationLevel(indicatorCalculateParams, result);
        // 工作履历（安检工作年限）
        this.workingYears(indicatorCalculateParams, result);
        // 出勤投入(上岗时长)
        this.avgWorkingHours(indicatorCalculateParams, result);

        return success(result);
    }

    /**
     * 能力画像-明细
     */
    @Cacheable(
            value = "statistics_list",
            keyGenerator = "statisticsKeyGenerator",
            unless = "!T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isSuccess(#result) ||T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isEmptyData(#result)"
    )
    @GetMapping("/detail")
    public AjaxResult detail(BaseLargeScreenQueryParamDto dto) {
        // 判空处理
        if (ObjectUtil.isNull(dto.getDeptId())) {
            dto.setDeptId(getDeptId());
        }
        if (ObjectUtil.isNull(dto.getDeptId())) {
            return error("部门ID不能为空");
        }

        IndicatorCalculateParams indicatorCalculateParams = this.appendParams(dto);

        // 返回结果
        List<SysLargeScreenDetailDto> result = new ArrayList<>();

        // 人均巡检问题数
        List<SysLargeScreenDetailDto> checkList = checkLargeScreenService.detail(dto);
        Map<Long, BigDecimal> checkCountMap = checkList.stream().collect(Collectors.toMap(SysLargeScreenDetailDto::getId, SysLargeScreenDetailDto::getCheckCount, (oldValue, newValue) -> newValue));

        // 返回结果处理
        SysDept sysDept = deptService.selectDeptById(dto.getDeptId());
        if (StrUtil.equals(DeptTypeEnum.STATION.getCode(), sysDept.getDeptType()) || StrUtil.equals(DeptTypeEnum.BRIGADE.getCode(), sysDept.getDeptType()) || StrUtil.equals(DeptTypeEnum.MANAGER.getCode(), sysDept.getDeptType())) {
            indicatorCalculateParams.setUserType(StrUtil.equals(DeptTypeEnum.STATION.getCode(), sysDept.getDeptType()) ? UserType.BRIGADE : StrUtil.equals(DeptTypeEnum.BRIGADE.getCode(), sysDept.getDeptType()) ? UserType.DEPARTMENT : UserType.TEAM);
            SysDept temp = new SysDept();
            temp.setParentId(dto.getDeptId());
            List<SysDept> deptList = deptService.selectDeptInfoAll(temp);
            deptList.forEach(item -> {
                SysLargeScreenDetailDto resultItem = new SysLargeScreenDetailDto();
                resultItem.setId(item.getDeptId());
                resultItem.setName(item.getDeptName());
                resultItem.setCheckCount(checkCountMap.getOrDefault(item.getDeptId(), BigDecimal.ZERO));
                //获取指标
                indicatorCalculateParams.setDeptId(item.getDeptId());
                List<SysUser> sysUsers = iSysUserService.selectUserListByRoleKeyAndDeptId(Arrays.asList(RoleTypeEnum.banzuzhang.getCode(), RoleTypeEnum.SecurityCheck.getCode()), item.getDeptId());
                indicatorCalculateParams.setUserIds(sysUsers.stream().map(SysUser::getUserId).collect(Collectors.toList()));
                this.qualificationLevel(indicatorCalculateParams, resultItem);
                this.avgSeizureCount(indicatorCalculateParams, resultItem);
                this.avgWorkingDays(indicatorCalculateParams, resultItem);
                this.avgWorkingHours(indicatorCalculateParams, resultItem);
                this.avgTestScore(indicatorCalculateParams, resultItem);
                result.add(resultItem);
            });
        } else if (StrUtil.equals(DeptTypeEnum.TEAMS.getCode(), sysDept.getDeptType())) {
            indicatorCalculateParams.setUserType(UserType.PERSONAL);
            List<SysUser> sysUsers = iSysUserService.selectUserListByRoleKeyAndDeptId(Arrays.asList(RoleTypeEnum.banzuzhang.getCode(), RoleTypeEnum.SecurityCheck.getCode()), dto.getDeptId());
            sysUsers.forEach(item -> {
                SysLargeScreenDetailDto resultItem = new SysLargeScreenDetailDto();
                resultItem.setId(item.getUserId());
                resultItem.setName(item.getNickName());
                resultItem.setCheckCount(checkCountMap.getOrDefault(item.getUserId(), BigDecimal.ZERO));
                //获取指标
                indicatorCalculateParams.setUserId(item.getUserId());
                this.qualificationLevel(indicatorCalculateParams, resultItem);
                this.avgSeizureCount(indicatorCalculateParams, resultItem);
                this.avgWorkingDays(indicatorCalculateParams, resultItem);
                this.avgWorkingHours(indicatorCalculateParams, resultItem);
                this.avgTestScore(indicatorCalculateParams, resultItem);
                result.add(resultItem);
            });
        } else {
            return error("部门类型数据错误");
        }

        return success(result);
    }

    /**
     * 工作画像-总体概览
     */
    @Cacheable(
            value = "statistics_data",
            keyGenerator = "statisticsKeyGenerator",
            unless = "!T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isSuccess(#result) ||T(com.sundot.airport.common.cache.StatisticsCacheConditionUtil).isEmptyData(#result)"
    )
    @GetMapping("/workingPortrait")
    public AjaxResult workingPortrait(BaseLargeScreenQueryParamDto dto) {
        // 返回结果
        SysLargeScreenWorkingPortraitDto result = new SysLargeScreenWorkingPortraitDto();

        // 工作产出和管理推动查询条件
        CheckLargeScreenCorrectionQueryParamDto checkQueryParam = new CheckLargeScreenCorrectionQueryParamDto();
        checkQueryParam.setDeptId(dto.getDeptId());
        checkQueryParam.setStartDate(dto.getStartDate());
        checkQueryParam.setEndDate(dto.getEndDate());
        checkQueryParam.setSpecifiedDate(dto.getSpecifiedDate());
        checkQueryParam.setProcessStatus("3");//ProcessStatusEnum.ARCHIVED.getCode()-归档
        // 工作产出
        List<CheckLargeScreenCommonDto> workOutputCheckList = checkLargeScreenService.workOutputCheck(checkQueryParam);
        result.setWorkOutput(workOutputCheckList.stream().map(CheckLargeScreenCommonDto::getTotal).reduce(BigDecimal.ZERO, BigDecimal::add));
        // 管理推动
        CheckLargeScreenCorrectionDto checkLargeScreenCorrectionDto = checkLargeScreenService.managementPromotionCorrection(checkQueryParam);
        result.setManagementPromotion(checkLargeScreenCorrectionDto.getOverTimeCompletedCount().add(checkLargeScreenCorrectionDto.getOverTimeUnfinishedCount()));
        //在岗时长
        SysDept sysDept = deptService.selectDeptById(dto.getDeptId());
        IndicatorCalculateParams indicatorCalculateParams = this.appendParams(dto);
        indicatorCalculateParams.setUserType(StrUtil.equals(DeptTypeEnum.STATION.getCode(), sysDept.getDeptType()) ? UserType.STATION : UserType.BRIGADE);
        indicatorCalculateParams.setDeptId(dto.getDeptId());
        List<SysUser> sysUsers = iSysUserService.selectUserListByRoleKeyAndDeptId(Arrays.asList(RoleTypeEnum.banzuzhang.getCode(), RoleTypeEnum.SecurityCheck.getCode()), dto.getDeptId());
        indicatorCalculateParams.setUserIds(sysUsers.stream().map(SysUser::getUserId).collect(Collectors.toList()));
        SysLargeScreenDetailDto detail = new SysLargeScreenDetailDto();
        this.avgWorkingHours(indicatorCalculateParams, detail);
        result.setAvgWorkingHours(detail.getAvgWorkingHours());
        return success(result);
    }

    /**
     * 根据用户编号获取详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping(value = {"/", "/{userId}"})
    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) {
        AjaxResult ajax = AjaxResult.success();
        if (StringUtils.isNotNull(userId)) {
            userService.checkUserDataScope(userId);
            SysUser sysUser = userService.selectUserById(userId);
            if (StringUtils.isNotEmpty(sysUser.getTeamCooperation())) {
                List<Long> list = Arrays.stream(sysUser.getTeamCooperation().split(",")).map(Long::valueOf).collect(Collectors.toList());
                sysUser.setTeamCooperationList(userService.selectByUserIdList(list));
            }
            ajax.put(AjaxResult.DATA_TAG, sysUser);
            ajax.put("postIds", postService.selectPostListByUserId(userId));
            ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
        }
        List<SysRole> roles = roleService.selectRoleAll();
        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        ajax.put("posts", postService.selectPostAll());
        return ajax;
    }

    /**
     * 新增用户
     */
    @PreAuthorize("@ss.hasPermi('system:user:add')")
    @Log(title = "用户管理", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@Validated @RequestBody SysUser user) {
        deptService.checkDeptDataScope(user.getDeptId());
        roleService.checkRoleDataScope(user.getRoleIds());
        if (!userService.checkUserNameUnique(user)) {
            return error("新增用户'" + user.getUserName() + "'失败，登录账号已存在");
        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
            return error("新增用户'" + user.getUserName() + "'失败，手机号码已存在");
        } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
            return error("新增用户'" + user.getUserName() + "'失败，邮箱账号已存在");
        }
        user.setCreateBy(getUsername());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        return toAjax(userService.insertUser(user));
    }

    /**
     * 修改用户
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@Validated @RequestBody SysUser user) {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        deptService.checkDeptDataScope(user.getDeptId());
        roleService.checkRoleDataScope(user.getRoleIds());
        if (!userService.checkUserNameUnique(user)) {
            return error("修改用户'" + user.getUserName() + "'失败，登录账号已存在");
        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
            return error("修改用户'" + user.getUserName() + "'失败，手机号码已存在");
        } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
            return error("修改用户'" + user.getUserName() + "'失败，邮箱账号已存在");
        }
        user.setUpdateBy(getUsername());
        redisCache.expire(CacheConstants.USER_INFO_KEY + user.getUserId(), 0);
        redisCache.expire(CacheConstants.USER_INFO_KEY + user.getUserName(), 0);
        return toAjax(userService.updateUser(user));
    }

    /**
     * 删除用户
     */
    @PreAuthorize("@ss.hasPermi('system:user:remove')")
    @Log(title = "用户管理", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public AjaxResult remove(@PathVariable Long[] userIds) {
        if (ArrayUtils.contains(userIds, getUserId())) {
            return error("当前用户不能删除");
        }
        return toAjax(userService.deleteUserByIds(userIds));
    }

    /**
     * 重置密码
     */
    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/resetPwd")
    public AjaxResult resetPwd(@RequestBody SysUser user) {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        user.setUpdateBy(getUsername());
        return toAjax(userService.resetPwd(user));
    }

    /**
     * 状态修改
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public AjaxResult changeStatus(@RequestBody SysUser user) {
        userService.checkUserAllowed(user);
        userService.checkUserDataScope(user.getUserId());
        user.setUpdateBy(getUsername());
        return toAjax(userService.updateUserStatus(user));
    }

    /**
     * 根据用户编号获取授权角色
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping("/authRole/{userId}")
    public AjaxResult authRole(@PathVariable("userId") Long userId) {
        AjaxResult ajax = AjaxResult.success();
        SysUser user = userService.selectUserById(userId);
        List<SysRole> roles = roleService.selectRolesByUserId(userId);
        ajax.put("user", user);
        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
        redisCache.expire(CacheConstants.USER_INFO_KEY + user.getUserId(), 0);
        redisCache.expire(CacheConstants.USER_INFO_KEY + user.getUserName(), 0);
        return ajax;
    }

    /**
     * 用户授权角色
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "用户管理", businessType = BusinessType.GRANT)
    @PutMapping("/authRole")
    public AjaxResult insertAuthRole(Long userId, Long[] roleIds) {
        userService.checkUserDataScope(userId);
        roleService.checkRoleDataScope(roleIds);
        userService.insertUserAuth(userId, roleIds);
        redisCache.expire(CacheConstants.USER_INFO_KEY + userId, 0);
        return success();
    }

    /**
     * 获取部门树列表
     */
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/deptTree")
    public AjaxResult deptTree(SysDept dept) {
        return success(deptService.selectDeptTreeList(dept));
    }

    /**
     * 获取部门及用户树列表
     */
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/deptUserTree")
    public AjaxResult deptUserTree(SysDept dept) {
        return success(deptService.selectDeptUserTreeList(dept));
    }

    /**
     * 获取全部用户列表
     */
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/listAll")
    public AjaxResult listAll(SysUser user) {
        List<SysUser> list = userService.selectUserList(user);
        return success(list);
    }

    /**
     * 通过用户ID查询用户各级领导
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping("/selectDeptLeaderByUserId")
    public AjaxResult selectDeptLeaderByUserId(@RequestParam("userId") Long userId, @RequestParam("deptType") String deptType) {
        return AjaxResult.success(userService.selectDeptLeaderByUserId(userId, deptType));
    }

    /**
     * 重置班组长和安检员的岗位为旅检的所有二级岗位
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "重置班组长和安检员的岗位为旅检的所有二级岗位", businessType = BusinessType.UPDATE)
    @GetMapping("/resetUserPost")
    public AjaxResult resetUserPost() {
        return toAjax(userService.resetUserPost());
    }

    /**
     * 重置指定部门中指定角色的人员的指定岗位
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "重置指定部门中指定角色的人员的指定岗位", businessType = BusinessType.UPDATE)
    @PostMapping("/resetUserPostByDept")
    public AjaxResult resetUserPostByDept(@RequestBody ResetUserPostDto resetUserPostDto) {
        return toAjax(userService.resetUserPostByDept(resetUserPostDto));
    }

    /**
     * 重置指定人员的指定角色
     */
    @PreAuthorize("@ss.hasPermi('system:user:edit')")
    @Log(title = "重置指定人员的指定角色", businessType = BusinessType.UPDATE)
    @PostMapping("/resetUserRole")
    public AjaxResult resetUserRole(@RequestBody ResetUserRoleDto resetUserRoleDto) {
        return toAjax(userService.resetUserRole(resetUserRoleDto));
    }

    /**
     * 根据用户ID获取岗位选择框列表
     */
    @PreAuthorize("@ss.hasPermi('system:user:query')")
    @GetMapping(value = {"/getPostListsByUserId/{userId}"})
    public AjaxResult getPostListsByUserId(@PathVariable("userId") Long userId) {
        return AjaxResult.success(postService.selectPostListsByUserId(userId));
    }

    /**
     * 获取用户画像-指标
     *
     * @return
     */
    private IndicatorCalculateParams appendParams(BaseLargeScreenQueryParamDto dto) {
        IndicatorCalculateParams params = new IndicatorCalculateParams();
        params.setIndicatorTypes(Arrays.asList("qualificationLevel", "workingDate", "workingHours", "effectiveSeizureCount", "workYears", "securityWorkYears"));
        // 设置默认时间范围
        java.util.Date endTime = Optional.ofNullable(dto.getEndDate()).orElse(new java.util.Date());
        java.util.Date startTime = Optional.ofNullable(dto.getStartDate())
                .orElse(java.util.Date.from(endTime.toInstant().minusSeconds(7862400L))); // 91天

        params.setStartTime(startTime);
        params.setEndTime(endTime);
        return params;
    }

    /**
     * 获取平均查获数量
     *
     * @param params
     * @param detail
     */
    private void avgSeizureCount(IndicatorCalculateParams params, SysLargeScreenDetailDto detail) {
        ModularIndicatorResult indicators = userPortraitService.getIndicators(params, Arrays.asList("item"));
        if (indicators == null) {
            detail.setAvgSeizureCount(BigDecimal.ZERO);
            return;
        }

        ItemSeizureModuleIndicatorResult itemResult = (ItemSeizureModuleIndicatorResult) indicators.getModuleResult("item");
        if (itemResult == null) {
            detail.setAvgSeizureCount(BigDecimal.ZERO);
            return;
        }

        if (UserType.PERSONAL.equals(params.getUserType())) {
            detail.setAvgSeizureCount(itemResult.getEffectiveSeizureCount() != null ?
                    new BigDecimal(itemResult.getEffectiveSeizureCount().toString()) : BigDecimal.ZERO);
        } else {
            Object effectiveSeizureCount = itemResult.getEffectiveSeizureCount();
            if (effectiveSeizureCount instanceof SeizureStats) {
                SeizureStats seizureStats = (SeizureStats) effectiveSeizureCount;
                if (seizureStats.getTotalCount() != 0) {
                    detail.setAvgSeizureCount(new BigDecimal(seizureStats.getTotalCount()));
                } else {
                    detail.setAvgSeizureCount(BigDecimal.ZERO);
                }
            } else {
                detail.setAvgSeizureCount(BigDecimal.ZERO);
            }
        }
    }

    /**
     * 获取平均上岗时长
     *
     * @param params
     * @param detail
     */
    private void avgWorkingHours(IndicatorCalculateParams params, SysLargeScreenDetailDto detail) {
        ModularIndicatorResult indicators = userPortraitService.getIndicators(params, Arrays.asList("attendance"));
        if (indicators == null) {
            detail.setAvgWorkingHours(BigDecimal.ZERO);
            return;
        }

        AttendanceModuleIndicatorResult attendanceResult = (AttendanceModuleIndicatorResult) indicators.getModuleResult("attendance");
        if (attendanceResult == null) {
            detail.setAvgWorkingHours(BigDecimal.ZERO);
            return;
        }

        if (UserType.PERSONAL.equals(params.getUserType())) {
            detail.setAvgWorkingHours(attendanceResult.getWorkingHours() != null ?
                    new BigDecimal(attendanceResult.getWorkingHours().toString()) : BigDecimal.ZERO);
        } else {
            Object workingHours = attendanceResult.getWorkingHours();
            if (workingHours instanceof WorkHoursStats) {
                WorkHoursStats workHoursStats = (WorkHoursStats) workingHours;
                detail.setAvgWorkingHours(workHoursStats.getAveragePersonnel() != null ?
                        workHoursStats.getAveragePersonnel() : BigDecimal.ZERO);
            } else {
                detail.setAvgWorkingHours(BigDecimal.ZERO);
            }
        }
    }

    /**
     * 获取平均出勤天数
     *
     * @param params
     * @param detail
     */
    private void avgWorkingDays(IndicatorCalculateParams params, SysLargeScreenDetailDto detail) {
        ModularIndicatorResult indicators = userPortraitService.getIndicators(params, Arrays.asList("attendance"));
        if (indicators == null) {
            detail.setAvgWorkingDays(BigDecimal.ZERO);
            return;
        }

        AttendanceModuleIndicatorResult attendanceResult = (AttendanceModuleIndicatorResult) indicators.getModuleResult("attendance");
        if (attendanceResult == null) {
            detail.setAvgWorkingDays(BigDecimal.ZERO);
            return;
        }

        if (UserType.PERSONAL.equals(params.getUserType())) {
            detail.setAvgWorkingDays(attendanceResult.getWorkingDate() != null ?
                    new BigDecimal(attendanceResult.getWorkingDate().toString()) : BigDecimal.ZERO);
        } else {
            Object workingDate = attendanceResult.getWorkingDate();
            if (workingDate instanceof WorkDateStats) {
                WorkDateStats workDateStats = (WorkDateStats) workingDate;
                detail.setAvgWorkingDays(workDateStats.getAveragePersonnel() != null ?
                        workDateStats.getAveragePersonnel() : BigDecimal.ZERO);
            } else {
                detail.setAvgWorkingDays(BigDecimal.ZERO);
            }
        }
    }

    /**
     * 获取资质等级
     *
     * @param params
     * @param detail
     */
    private void qualificationLevel(IndicatorCalculateParams params, SysLargeScreenDetailDto detail) {
        ModularIndicatorResult indicators = userPortraitService.getIndicators(params, Arrays.asList("system"));
        if (indicators == null) {
            detail.setQualificationLevel("0");
            return;
        }

        IndicatorResult systemResult = (IndicatorResult) indicators.getModuleResult("system");
        if (systemResult == null) {
            detail.setQualificationLevel("0");
            return;
        }

        if (UserType.PERSONAL.equals(params.getUserType())) {
            String qualificationLevel = systemResult.getQualificationLevel();
            detail.setQualificationLevel(qualificationLevel != null ? qualificationLevel : "0");
        } else {
            List<QualificationStats> qualificationLevelStats = systemResult.getQualificationLevelStats();
            if (qualificationLevelStats != null) {
                final String FIRST_LEVEL = "高级";
                Integer reduce = qualificationLevelStats.stream()
                        .filter(qualificationStats -> FIRST_LEVEL.equals(qualificationStats.getLevelName()))
                        .map(QualificationStats::getCount)
                        .reduce(0, Integer::sum);
                detail.setQualificationLevel(reduce.toString());
            } else {
                detail.setQualificationLevel("0");
            }
        }
    }

    /**
     * 个人获取工作年限
     */
    private void workingYears(IndicatorCalculateParams params, SysLargeScreenDetailDto detail) {
        ModularIndicatorResult indicators = userPortraitService.getIndicators(params, Arrays.asList("system"));
        if (indicators == null) {
            detail.setWorkYears(BigDecimal.ZERO);
        }
        IndicatorResult systemResult = (IndicatorResult) indicators.getModuleResult("system");
        if (systemResult == null) {
            detail.setWorkYears(BigDecimal.ZERO);
            return;
        }
        if (UserType.PERSONAL.equals(params.getUserType())) {
            Integer workYears = systemResult.getSecurityWorkYears();
            detail.setWorkYears(workYears != null ? new BigDecimal(workYears) : BigDecimal.ZERO);
        } else {
            WorkExperienceStats securityWorkYearsStats = systemResult.getSecurityWorkYearsStats();
            if (securityWorkYearsStats != null && securityWorkYearsStats.getAverageWorkYears() != null) {
                detail.setWorkYears(BigDecimal.valueOf(securityWorkYearsStats.getAverageWorkYears()));
            } else {
                detail.setWorkYears(BigDecimal.ZERO);
            }
        }
    }


    /**
     * 获取测试平均分
     *
     * @param params
     * @param detail
     */
    private void avgTestScore(IndicatorCalculateParams params, SysLargeScreenDetailDto detail) {
        java.util.Date startTime = params.getStartTime();
        java.util.Date endTime = params.getEndTime();

        // 根据用户类型查询
        if (UserType.PERSONAL.equals(params.getUserType())) {
            // 个人：查询该用户的平均分
            Long userId = params.getUserId();
            BigDecimal avgScore = calculateUserAvgScore(userId, startTime, endTime);
            detail.setTestScore(avgScore);
        } else {
            // 组织：查询该部门下所有成员的平均分
            Long deptId = params.getDeptId();
            BigDecimal avgScore = calculateDeptAvgScore(deptId, startTime, endTime);
            detail.setTestScore(avgScore);
        }
    }

    /**
     * 计算个人平均分
     */
    private BigDecimal calculateUserAvgScore(Long userId, java.util.Date startTime, java.util.Date endTime) {
        LambdaQueryWrapper<DailyTask> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DailyTask::getDtUserId, userId);
        wrapper.ge(DailyTask::getDtBusinessDate, Date.valueOf(
                new java.text.SimpleDateFormat("yyyy-MM-dd").format(startTime)));
        wrapper.le(DailyTask::getDtBusinessDate, Date.valueOf(
                new java.text.SimpleDateFormat("yyyy-MM-dd").format(endTime)));
        wrapper.in(DailyTask::getDtStatus, "COMPLETED", "EXPIRED");
        wrapper.eq(DailyTask::getDelStatus, 0);

        List<DailyTask> tasks = dailyTaskMapper.selectList(wrapper);

        if (tasks.isEmpty()) {
            return BigDecimal.ZERO;
        }

        BigDecimal totalScore = tasks.stream()
                .map(task -> "EXPIRED".equals(task.getDtStatus()) ? BigDecimal.ZERO : task.getDtTotalScore())
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        return totalScore.divide(new BigDecimal(tasks.size()), 2, RoundingMode.HALF_UP);
    }

    /**
     * 计算部门平均分（所有成员的平均分）
     */
    private BigDecimal calculateDeptAvgScore(Long deptId, java.util.Date startTime, java.util.Date endTime) {
        // 1. 获取部门下所有用户
        List<SysUser> users = iSysUserService.selectUserByDeptId(deptId);

        if (users.isEmpty()) {
            return BigDecimal.ZERO;
        }

        // 2. 收集所有用户ID
        List<Long> userIds = users.stream()
                .map(SysUser::getUserId)
                .collect(Collectors.toList());

        // 3. 查询这些用户的所有任务
        LambdaQueryWrapper<DailyTask> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(DailyTask::getDtUserId, userIds);
        wrapper.ge(DailyTask::getDtBusinessDate, Date.valueOf(
                new java.text.SimpleDateFormat("yyyy-MM-dd").format(startTime)));
        wrapper.le(DailyTask::getDtBusinessDate, Date.valueOf(
                new java.text.SimpleDateFormat("yyyy-MM-dd").format(endTime)));
        wrapper.in(DailyTask::getDtStatus, "COMPLETED", "EXPIRED");
        wrapper.eq(DailyTask::getDelStatus, 0);

        List<DailyTask> tasks = dailyTaskMapper.selectList(wrapper);

        if (tasks.isEmpty()) {
            return BigDecimal.ZERO;
        }

        // 4. 计算所有任务的平均分
        BigDecimal totalScore = tasks.stream()
                .map(task -> "EXPIRED".equals(task.getDtStatus()) ? BigDecimal.ZERO : task.getDtTotalScore())
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        return totalScore.divide(new BigDecimal(tasks.size()), 2, RoundingMode.HALF_UP);
    }

    /**
     * 计算population接口的测试平均分
     * 根据userId或deptId查询抽问抽答的平均分
     */
    private BigDecimal calculatePopulationTestScore(BaseLargeScreenQueryParamDto dto) {
        // 设置时间范围
        java.util.Date endTime = Optional.ofNullable(dto.getEndDate()).orElse(new java.util.Date());
        java.util.Date startTime = Optional.ofNullable(dto.getStartDate())
                .orElse(java.util.Date.from(endTime.toInstant().minusSeconds(7862400L))); // 91天

        // 判断是个人还是部门
        if (ObjectUtil.isNotNull(dto.getUserId())) {
            // 个人维度：直接查询该用户的平均分
            return calculateUserAvgScore(dto.getUserId(), startTime, endTime);
        } else if (ObjectUtil.isNotNull(dto.getDeptId())) {
            // 部门维度：查询该部门及所有下级部门的平均分
            return calculateDeptAvgScoreByDeptId(dto.getDeptId(), startTime, endTime);
        }

        return BigDecimal.ZERO;
    }

    /**
     * 根据部门ID计算平均分（基于dt_dept_id查询）
     * 需要递归查找所有下级部门
     */
    private BigDecimal calculateDeptAvgScoreByDeptId(Long deptId, java.util.Date startTime, java.util.Date endTime) {
        // 1. 获取该部门及所有下级部门的ID列表
        List<Long> deptIds = getAllSubDeptIds(deptId);

        if (deptIds.isEmpty()) {
            return BigDecimal.ZERO;
        }

        // 2. 查询这些部门的所有任务（通过dt_dept_id）
        LambdaQueryWrapper<DailyTask> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(DailyTask::getDtDeptId, deptIds);
        wrapper.ge(DailyTask::getDtBusinessDate, Date.valueOf(
                new java.text.SimpleDateFormat("yyyy-MM-dd").format(startTime)));
        wrapper.le(DailyTask::getDtBusinessDate, Date.valueOf(
                new java.text.SimpleDateFormat("yyyy-MM-dd").format(endTime)));
        wrapper.in(DailyTask::getDtStatus, "COMPLETED", "EXPIRED");
        wrapper.eq(DailyTask::getDelStatus, 0);

        List<DailyTask> tasks = dailyTaskMapper.selectList(wrapper);

        if (tasks.isEmpty()) {
            return BigDecimal.ZERO;
        }

        // 3. 计算平均分（EXPIRED的任务分数算0）
        BigDecimal totalScore = tasks.stream()
                .map(task -> "EXPIRED".equals(task.getDtStatus()) ? BigDecimal.ZERO : task.getDtTotalScore())
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        return totalScore.divide(new BigDecimal(tasks.size()), 2, RoundingMode.HALF_UP);
    }

    /**
     * 获取指定部门及其所有下级部门的ID列表
     * 根据sys_dept表的层级关系递归查找
     */
    private List<Long> getAllSubDeptIds(Long deptId) {
        List<Long> result = new ArrayList<>();
        result.add(deptId); // 包含自己

        // 查询直接下级部门
        SysDept queryDept = new SysDept();
        queryDept.setParentId(deptId);
        List<SysDept> subDepts = deptService.selectDeptInfoAll(queryDept);

        // 递归查询所有下级部门
        for (SysDept subDept : subDepts) {
            if ("0".equals(subDept.getDelFlag())) { // 只包含未删除的部门
                result.addAll(getAllSubDeptIds(subDept.getDeptId()));
            }
        }

        return result;
    }
}
