package com.vctgo.system.service.impl;

import com.alibaba.nacos.shaded.com.google.common.base.Joiner;
import com.alibaba.nacos.shaded.com.google.common.base.Splitter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vctgo.common.core.constant.CacheConstants;
import com.vctgo.common.core.constant.UserConstants;
import com.vctgo.common.core.exception.ServiceException;
import com.vctgo.common.core.text.Convert;
import com.vctgo.common.core.utils.DateUtils;
import com.vctgo.common.core.utils.ServletUtils;
import com.vctgo.common.core.utils.SpringUtils;
import com.vctgo.common.core.utils.StrUtils;
import com.vctgo.common.core.utils.bean.BeanValidators;
import com.vctgo.common.core.web.domain.TenantEntity;
import com.vctgo.common.datascope.annotation.DataScope;
import com.vctgo.common.mybatisplus.aop.TemporaryIgnoreTables;
import com.vctgo.common.mybatisplus.constant.MybatisPageConstants;
import com.vctgo.common.redis.service.RedisService;
import com.vctgo.common.security.utils.SecurityUtils;
import com.vctgo.system.api.domain.*;
import com.vctgo.system.api.domain.dto.StaticsUserPermsDto;
import com.vctgo.system.api.domain.dto.SysUserDto;
import com.vctgo.system.api.model.LoginUser;
import com.vctgo.system.domain.*;
import com.vctgo.system.domain.SysPost;
import com.vctgo.system.domain.SysTeachStaff;
import com.vctgo.system.mapper.*;
import com.vctgo.system.service.ISysConfigService;
import com.vctgo.system.service.ISysUserService;
import com.vctgo.system.service.SystemCommonService;
import com.vctgo.system.util.ConstantUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import javax.validation.Validator;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户 业务层处理
 *
 * @author vctgo
 */
@Service
public class SysUserServiceImpl implements ISysUserService {
    private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysPlatformUserMapper sysPlatformUserMapper;

    @Autowired
    private SysRoleMapper roleMapper;

    @Autowired
    private SysDeptMapper deptMapper;

    @Autowired
    private SysPostMapper postMapper;

    @Autowired
    private SysUserRoleMapper userRoleMapper;

    @Autowired
    private SysUserPostMapper userPostMapper;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private SysTenantMapper tenantMapper;

    @Autowired
    private SysReClassUserMapper reClassUserMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    protected Validator validator;

    @Autowired
    private SysWechatUserMapper sysWechatUserMapper;

    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private SystemCommonService systemCommonService;

    @Value("${wechat.appid}")
    private String appId;

    @Value("${wechat.grantType}")
    private String type;

    @Value("${wechat.secret}")
    private String secret;

    @Value("${wechat.url}")
    private String url;

    @Value("${wechat.userInfoUrl}")
    private String userInfoUrl;


    @Value("${wechat.accessToken}")
    private String accessToken;


    @Value("${wechat.phoneNumber}")
    private String phoneNumber;


    @Autowired
    private SysTeachStaffMapper sysTeachStaffMapper;

    private final RestTemplate restTemplate;

    public SysUserServiceImpl() {
        this.restTemplate = new RestTemplate(new SimpleClientHttpRequestFactory());
    }


    @PostConstruct
    public void initTenantUser() {
        systemCommonService.loadingUserCache();
    }


    /**
     * 根据条件分页查询用户列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @TemporaryIgnoreTables
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public IPage<SysUser> selectUserPage(SysUser user) {
        Page mpPage = new Page(Convert.toLong(ServletUtils.getParameterToInt(MybatisPageConstants.PAGE_NUM), 1L)
                , Convert.toLong(ServletUtils.getParameterToInt(MybatisPageConstants.PAGE_SIZE), 10L));
        //获取当前租户类型，判断当前租户是集团租户还是独立幼儿园租户,去除超管的条件判断
        SysTenant sysTenant = tenantMapper.selectById(SecurityUtils.getTenantId());
        SecurityUtils.setTemporaryIgnoreTables(Collections.singletonList("sys_post"));
        if (1 == sysTenant.getTenantType()) {
            //获取集团租户对应的全部幼儿园租户
            SysTenant sysTenantGroup = new SysTenant();
            sysTenantGroup.setGardenId(sysTenant.getGardenId());
            List<SysTenant> sysTenantList = tenantMapper.selectSysTenantList(sysTenantGroup);
            List<Long> tenantIdGroupList = sysTenantList.stream().map(SysTenant::getId).collect(Collectors.toList());
            user.getParams().put("tenantIdGroupList", tenantIdGroupList);
            SecurityUtils.setTemporaryIgnoreTables(Arrays.asList("sys_user", "sys_dept", "sys_user_post", "sys_post", "sys_tenant", "sys_role", "sys_user_role"));
            user.getParams().put("dataScope", "");
        } else {
            SecurityUtils.setTemporaryIgnoreTables(Collections.singletonList("sys_user"));
            //幼儿园租户和独立园租户显示其下租户的用户信息，不设计到忽略用户表
            user.getParams().put("tenantId", sysTenant.getId());
        }
        if (user.getDeptId() != null) {
            SysDept deptInfo = deptMapper.selectDeptById(user.getDeptId());
            //判断是否查询集团租户的全部岗位信息
            if ("1".equals(deptInfo.getDeptType())) {
                user.getParams().put("tenantType", ConstantUtils.TENANT_TYPE_1);
            }
        }
        IPage<SysUser> sysUserIPage = userMapper.selectUserList(mpPage, user);
        if (!sysUserIPage.getRecords().isEmpty()) {
            List<SysRole> sysRoleList = roleMapper.selectRoleListByUserIdList(sysUserIPage.getRecords().stream().map(SysUser::getUserId).collect(Collectors.toList()));
            sysUserIPage.getRecords().forEach(sysUser -> {
                List<String> roleList = new ArrayList<>();
                sysRoleList.stream().filter(sysRole -> sysRole.getUserId().longValue()
                        == sysUser.getUserId().longValue()).forEach(sysRole ->
                        roleList.add(1 == SecurityUtils.getTenantType() ? sysRole.getTenantName() + "-" + sysRole.getRoleName() : sysRole.getRoleName()));
                sysUser.setRole(Joiner.on(",").join(roleList));
            });
        }
        return sysUserIPage;
    }

    /**
     * 根据条件查询用户列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<SysUser> selectUserList(SysUser user) {
        return userMapper.selectUserList(user);
    }

    @Override
    public List<SysDept> userListByTenantIdAndNickNameWithPhoneNumber(String tenantId,
                                                                      String nickName,
                                                                      String phoneNumber,
                                                                      Long userId) {
        List<SysDept> sysDeptList = sysDeptMapper.selectUserByDept(tenantId, nickName, phoneNumber, userId);
        if (StringUtils.hasLength(nickName) && !CollectionUtils.isEmpty(sysDeptList)) {
            List<SysDept> sysDeptTmpList = treeToList(sysDeptList);
            String ancestors = Joiner.on(",").join(sysDeptTmpList.stream()
                    .filter(sysDept -> !CollectionUtils.isEmpty(sysDept.getSysUserList()))
                    .map(SysDept::getAncestors)
                    .collect(Collectors.toSet()));
            Set<String> ancestorsSet = Splitter.on(",").splitToList(ancestors).stream()
                    .sorted()
                    .collect(Collectors.toSet());
            sysDeptTmpList.removeIf(sysDept -> !ancestorsSet.contains(sysDept.getDeptId().toString()));
            sysDeptList = convertSysDeptListToTree(sysDeptTmpList, Long.parseLong(ancestorsSet.stream().findFirst().get()));
        }
        SecurityUtils.removeTemporaryIgnoreTables();
        return sysDeptList;
    }

    private List<SysDept> treeToList(List<SysDept> sysDeptList) {
        List<SysDept> result = new ArrayList<>();
        for (SysDept entity : sysDeptList) {
            entity.setAncestors(entity.getAncestors() + "," + entity.getDeptId());
            result.add(entity);
            List<SysDept> childMsg = entity.getChildren();
            if (childMsg != null && !childMsg.isEmpty()) {
                List<SysDept> entityList = this.treeToList(childMsg);
                result.addAll(entityList);
            }
        }
        if (!result.isEmpty()) {
            for (SysDept entity : result) {
                entity.setChildren(null);
            }
        }
        return result;
    }

    /**
     * 将文件信息列表改成文件信息树状
     *
     * @param list
     * @param parentId
     * @return
     */
    // 递归方法
    private List<SysDept> convertSysDeptListToTree(List<SysDept> list, long parentId) {
        return list.stream()
                .filter(sysDept -> Objects.nonNull(sysDept.getParentId()) && parentId == sysDept.getParentId())
                .peek(sysDept -> sysDept.setChildren(convertSysDeptListToTree(list, sysDept.getDeptId())))
                .collect(Collectors.toList());
    }

    @Override
    public List<SysUserTempalte> userListByTenantIds(String tenantIds) {
        List<SysUserTempalte> sysUserTempalteList = new ArrayList<>();

        // 取出幼儿园端用户
        LambdaQueryWrapper<SysUser> sysUserWrapper = new LambdaQueryWrapper<>();
        sysUserWrapper.eq(SysUser::getDelFlag, "0");
        sysUserWrapper.eq(StrUtils.isNotEmpty(tenantIds), TenantEntity::getTenantId, tenantIds.replace("9999", "").replace(",", ""));
        sysUserWrapper.select(SysUser::getNickName, SysUser::getUserId);
        sysUserTempalteList.addAll(userMapper.selectList(sysUserWrapper));

        // 取出平台端用户
        LambdaQueryWrapper<SysPlatformUser> sysPlatformUserWrapper = new LambdaQueryWrapper<>();
        sysPlatformUserWrapper.eq(SysPlatformUser::getDelFlag, "0");
        sysPlatformUserWrapper.select(SysUserTempalte::getNickName, SysPlatformUser::getUserId);
        sysUserTempalteList.addAll(sysPlatformUserMapper.selectList(sysPlatformUserWrapper));
        return sysUserTempalteList;
    }

    /**
     * 根据条件分页查询已分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @TemporaryIgnoreTables
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public IPage<SysUser> selectAllocatedList(SysUser user) {
        if (1 == SecurityUtils.getTenantType()) {
            SecurityUtils.setTemporaryIgnoreTables(Arrays.asList("sys_role", "sys_user_role", "sys_user", "sys_dept",
                    "sys_user_post", "sys_post"));
        } else if (2 == SecurityUtils.getTenantType()) {
            SecurityUtils.setTemporaryIgnoreTables(Arrays.asList("sys_user_post", "sys_post"));
        }
        Page mpPage = new Page(Convert.toLong(ServletUtils.getParameterToInt(MybatisPageConstants.PAGE_NUM), 1L)
                , Convert.toLong(ServletUtils.getParameterToInt(MybatisPageConstants.PAGE_SIZE), 10L));
        user.setTenantType(SecurityUtils.getTenantType());
        IPage<SysUser> sysUserIPage = userMapper.selectAllocatedList(mpPage, user);
        List<String> createByList = sysUserIPage.getRecords().stream().map(SysUser::getCreateBy).distinct().collect(Collectors.toList());
        if (!createByList.isEmpty()) {
            SecurityUtils.setTemporaryIgnoreTables(Collections.singletonList("sys_user"));
            LambdaQueryWrapper<SysUser> sysUserWrapper = new LambdaQueryWrapper<>();
            sysUserWrapper.eq(SysUser::getDelFlag, "0");
            sysUserWrapper.in(SysUser::getUserAccount, createByList);
            List<SysUser> sysUserList = userMapper.selectList(sysUserWrapper);
            sysUserIPage.getRecords().forEach(sysUserTmp -> {
                Optional<SysUser> sysUserOptional = sysUserList.stream().filter(sysUser -> sysUser.getUserAccount().equals(sysUserTmp.getCreateBy())).findFirst();
                sysUserOptional.ifPresent(sysUser -> sysUserTmp.setCreateUserName(sysUser.getNickName()));
            });
            SecurityUtils.removeTemporaryIgnoreTables(Collections.singletonList("sys_user"));
        }
        return sysUserIPage;
    }

    /**
     * 根据条件分页查询未分配用户角色列表
     *
     * @param user 用户信息
     * @return 用户信息集合信息
     */
    @TemporaryIgnoreTables
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public IPage<SysUser> selectUnallocatedList(SysUser user) {
        if ("1".equals(SecurityUtils.getTenantType().toString())) {

            // 在集团租户下，操作集团创建的角色
            if (SecurityUtils.getTenantId().longValue() == user.getTenantId().longValue()) {
                SecurityUtils.setTemporaryIgnoreTables(Arrays.asList("sys_user_post", "up", "sys_post"));
            } else {
                // 在集团租户下，操作非集团角色
                SecurityUtils.setTemporaryIgnoreTables(Arrays.asList("d", "r", "ur", "u", "uu", "sur", "up", "p", "sys_role",
                        "sys_user_role", "sys_user", "sys_dept", "sys_user_post", "sys_post"));
                user.setTenantIdList(new ArrayList<>(Collections.singletonList(user.getTenantId())));
                user.setTenantId(null);
            }
        } else if (2 == SecurityUtils.getTenantType()) {
            SecurityUtils.setTemporaryIgnoreTables(Arrays.asList("sys_user_post", "up", "sys_post"));
        }
        Page mpPage = new Page(Convert.toLong(ServletUtils.getParameterToInt(MybatisPageConstants.PAGE_NUM), 1L), Convert.toLong(ServletUtils.getParameterToInt(MybatisPageConstants.PAGE_SIZE), 10L));
        IPage<SysUser> sysUserIPage = userMapper.selectUnallocatedList(mpPage, user);
        List<String> createByList = sysUserIPage.getRecords().stream().map(SysUser::getCreateBy).distinct().collect(Collectors.toList());
        if (!createByList.isEmpty()) {
            SecurityUtils.setTemporaryIgnoreTables(Collections.singletonList("sys_user"));
            LambdaQueryWrapper<SysUser> sysUserWrapper = new LambdaQueryWrapper<>();
            sysUserWrapper.eq(SysUser::getDelFlag, "0");
            sysUserWrapper.in(SysUser::getUserAccount, sysUserIPage.getRecords().stream().map(SysUser::getCreateBy).distinct().collect(Collectors.toList()));
            List<SysUser> sysUserList = userMapper.selectList(sysUserWrapper);
            sysUserIPage.getRecords().forEach(sysUserTmp -> {
                Optional<SysUser> sysUserOptional = sysUserList.stream().filter(sysUser -> sysUser.getUserAccount().equals(sysUserTmp.getCreateBy())).findFirst();
                sysUserOptional.ifPresent(sysUser -> sysUserTmp.setCreateUserName(sysUser.getNickName()));
            });
            SecurityUtils.removeTemporaryIgnoreTables(Collections.singletonList("sys_user"));
        }
        return sysUserIPage;
    }

    /**
     * 通过用户名查询用户
     *
     * @param userName 用户名
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserByUserName(String userName) {
        return userMapper.selectUserByUserName(userName);
    }

    /**
     * 通过租户Id和用户名查询用户
     *
     * @param userName 用户名
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserByUserAccount(Long tenantId, String userName) {
        if (tenantId == null) {
            tenantId = SecurityUtils.getTenantId();
        }
        return userMapper.selectUserByUserAccount(tenantId, userName);
    }

    /**
     * 通过租户Id和用户名查询用户
     *
     * @param tenantId 租户Id
     * @return 用户对象信息
     */
    @Override
    public List<SysUser> selectUserListByParams(Long tenantId, String delFlag) {
        if (tenantId == null) {
            tenantId = SecurityUtils.getTenantId();
        }

        SysTenant sysTenant = tenantMapper.selectById(tenantId);
        Map<String, Object> params = new HashMap<>();
        params.put("tenantType", sysTenant.getTenantType());
        params.put("tenantId", sysTenant.getId());
        //默认查询没有删除的用户，其他服务调用此接口时，由于需要创建人的正常显示，可能会查询全部的用户
        params.put("delFlag", StrUtils.isNotEmpty(delFlag) && "all".equals(delFlag) ? "all" : "");
        return userMapper.selectUserListByParams(params);
    }

    /**
     * 通过用户ID查询用户
     *
     * @param userId 用户ID
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserById(Long userId) {
        SysUser sysUser = userMapper.selectUserById(userId);
        sysUser.getRoles().removeIf(sysRole -> Objects.isNull(sysRole.getRoleId()));
        return sysUser;
    }

    /**
     * 通过用户ID查询用户基本信息
     *
     * @param userId 用户ID
     * @return 用户对象信息
     */
    @Override
    public SysUser selectUserByUserId(Long userId, Long tenantId) {
        return userMapper.selectUserByUserId(userId, tenantId);
    }

    /**
     * 查询用户所属角色组
     *
     * @param userName 用户名
     * @return 结果
     */
    @Override
    public String selectUserRoleGroup(String userName) {
        List<SysRole> list = roleMapper.selectRolesByUserName(userName);
        if (CollectionUtils.isEmpty(list)) {
            return StrUtils.EMPTY;
        }
        return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(","));
    }

    /**
     * 查询用户所属岗位组
     *
     * @param userName 用户名
     * @return 结果
     */
    @Override
    public String selectUserPostGroup(String userName) {
        List<SysPost> list = postMapper.selectPostsByUserName(userName);
        if (CollectionUtils.isEmpty(list)) {
            return StrUtils.EMPTY;
        }
        return list.stream().map(SysPost::getPostName).collect(Collectors.joining(","));
    }

    @TemporaryIgnoreTables
    @Override
    public IPage<SysUserDto> selectPointPostUserList(String postCode, String nickName, String phoneNumber) {
        Page mpPage = new Page(Convert.toLong(ServletUtils.getParameterToInt(MybatisPageConstants.PAGE_NUM), 1L)
                , Convert.toLong(ServletUtils.getParameterToInt(MybatisPageConstants.PAGE_SIZE), 10L));
        SecurityUtils.setTemporaryIgnoreTables(Arrays.asList("sys_post"));
        return userMapper.selectPointPostUserList(mpPage, postCode, SecurityUtils.getTenantId(), nickName, phoneNumber);
    }

    /**
     * 校验用户名称是否唯一
     *
     * @param user 用户名称
     * @return 结果
     */
    @Override
    public boolean checkUserNameUnique(SysUser user) {
        Long userId = StrUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = userMapper.checkUserNameUnique(user.getUserName());
        if (StrUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验手机号码是否唯一
     *
     * @param user 用户信息
     * @return
     */
    @Override
    public boolean checkPhoneUnique(SysUser user) {
        Long userId = StrUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber());
        if (StrUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验email是否唯一
     *
     * @param user 用户信息
     * @return
     */
    @Override
    public boolean checkEmailUnique(SysUser user) {
        Long userId = StrUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
        SysUser info = userMapper.checkEmailUnique(user.getEmail());
        if (StrUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    /**
     * 校验用户是否允许操作
     *
     * @param user 用户信息
     */
    @Override
    public void checkUserAllowed(SysUser user) {
        if (StrUtils.isNotNull(user.getUserId()) && user.isAdmin()) {
            throw new ServiceException("不允许操作超级管理员用户");
        }
    }

    /**
     * 校验用户是否有数据权限
     *
     * @param userId 用户id
     */
    @TemporaryIgnoreTables
    @Override
    public void checkUserDataScope(Long userId) {
        if (!SysUser.isAdmin(SecurityUtils.getUserId())) {
            SysUser user = new SysUser();
            user.setUserId(userId);
            if (SecurityUtils.getTenantId() == 9999L || SecurityUtils.getTenantType() == 1) {
                SecurityUtils.setTemporaryIgnoreTables(Arrays.asList("sys_user", "sys_dept", "sys_user_post", "sys_post"));
            }
            List<SysUser> users = SpringUtils.getAopProxy(this).selectUserList(user);
            if (StrUtils.isEmpty(users)) {
                throw new ServiceException("没有权限访问用户数据！");
            }
        }
    }

    /**
     * 判断用户是否存在指定的权限
     *
     * @param staticsUserPermsDto 部门信息
     * @return 统计对象集合
     */
    @Override
    public Boolean judgeUserIsExistPointPerms(StaticsUserPermsDto staticsUserPermsDto) {
        return userMapper.judgeUserIsExistPointPerms(staticsUserPermsDto) > 0;
    }

    /**
     * 新增保存用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertUser(SysUser user) {
        // 新增用户信息
        int rows = userMapper.insert(user);
        // 新增用户岗位关联
        insertUserPost(user);
        // 新增用户与角色管理
        insertUserRole(user);

        // 更新redis中，当前租户的数据
        systemCommonService.synchronizedUserInfo(user);
        return rows;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertUserByVote(SysUser user) {
        // 幼儿园端新增用户
        user.setDelFlag(ConstantUtils.IS_DELETED_0);
        user.setUserName(user.getPhonenumber());
        user.setCreateById(SecurityUtils.getUserId());
        user.setCreateTime(DateUtils.getNowDate());
        user.setUserStatus("0");
        user.setAccountStatus(ConstantUtils.ACCOUNT_STATUS_2);
        user.setTenantId(SecurityUtils.getTenantId());
        user.setVerifyStatus(0);
        user.setSourceType(2);
        //默认密码采用随机生成
        String randomPassword = SecurityUtils.randomPassword(6);//随机密码6位
        String password = SecurityUtils.encryptPassword(randomPassword);
        user.setPassword(password);
        user.setUserAccount(user.getPhonenumber());
        user.setAccountDate(new Date());
        int result=userMapper.insert(user);
        //创建教职工账号
        SysTeachStaff sysTeachStaff = new SysTeachStaff();
        sysTeachStaff.setUserId(user.getUserId());
        sysTeachStaff.setUserName(user.getPhonenumber());
        sysTeachStaff.setPhonenumber(user.getPhonenumber());
        sysTeachStaffMapper.insert(sysTeachStaff);
        return result;
    }

    /**
     * 注册用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public boolean registerUser(SysUser user) {
        user.setCreateById(SecurityUtils.getUserId());
        return userMapper.insert(user) > 0;
    }

    /**
     * 修改保存用户信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @TemporaryIgnoreTables
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateUser(SysUser user) {
        SysUser beforeUser = userMapper.selectUserByUserId(user.getUserId(), null);
        if (1 == SecurityUtils.getTenantType()) {
            SecurityUtils.setTemporaryIgnoreTables(Collections.singletonList("sys_user_role"));
        }
        if ("1".equals(user.getUserStatus()) && StrUtils.isNotEmpty(beforeUser.getAccountStatus())) {
            //离职时，将用户账户更改为禁用状态
            user.setAccountStatus(ConstantUtils.ACCOUNT_STATUS_1);
        }

        Long userId = user.getUserId();
        // 删除用户与角色关联
        userRoleMapper.deleteUserRoleByUserId(userId);
        // 新增用户与角色管理
        insertUserRole(user);
        // 删除用户与岗位关联
        userPostMapper.deleteUserPostByUserId(userId);
        // 新增用户与岗位管理
        insertUserPost(user);
        //如果离职，将组织的主管清空
        if ("1".equals(user.getUserStatus()) || "Y".equals(user.getParams().get("clearLeader"))) {
            deptMapper.clearLeaderInfoByUserId(userId);
        }
        //判断当前用户手机号码是否变更，如果变更，则判断当前手机号码是否开通账号，如果开通，同步更新账号
        if (!beforeUser.getPhonenumber().equals(user.getPhonenumber()) && StrUtils.isNotEmpty(beforeUser.getUserAccount())) {
            user.setUserAccount(user.getPhonenumber());//新系统使用
            user.setUserName(user.getPhonenumber());   //旧系统使用

            // 退出登录
            Collection<String> keys = redisService.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
            for (String key : keys) {
                LoginUser onlineUser = redisService.getCacheObject(key);
                if (Objects.nonNull(onlineUser)
                        && Objects.nonNull(onlineUser.getSysUser())
                        && onlineUser.getUserid().longValue() == user.getUserId().longValue()) {
                    redisService.deleteObject(key);
                    break;
                }
            }
        }


        // 更新redis中的用户列表
        systemCommonService.synchronizedUserInfo(user);
        //注意，下方方法与上述方法不可互换位置
        if (beforeUser != null && !beforeUser.getNickName().equals(user.getNickName())) {
            userMapper.updateReTableNickName(userId, user.getNickName());
        }
        return userMapper.updateUser(user);
    }

    /**
     * 编辑用户账号
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateUserAccount(SysUser user) {
        Long userId = user.getUserId();
        // 删除用户与角色关联
        userRoleMapper.deleteUserRoleByUserId(userId);
        // 新增用户与角色管理
        insertUserRole(user);
        return userMapper.updateUser(user);
    }

    /**
     * 用户授权角色
     *
     * @param userId  用户ID
     * @param roleIds 角色组
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertUserAuth(Long userId, Long[] roleIds) {
        userRoleMapper.deleteUserRoleByUserId(userId);
        insertUserRole(userId, roleIds, SecurityUtils.getTenantId());
    }

    /**
     * 修改用户状态
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int updateUserStatus(SysUser user) {

        int successCount = userMapper.updateUser(user);
        //如果离职，将组织的主管清空
        deptMapper.clearLeaderInfoByUserId(user.getUserId());
        return successCount;
    }

    /**
     * 修改用户头像
     *
     * @param userName 用户名
     * @param avatar   头像地址
     * @return 结果
     */
    @Override
    public boolean updateUserAvatar(String userName, String avatar) {
        return userMapper.updateUserAvatar(userName, avatar) > 0;
    }

    /**
     * 重置用户密码
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    public int resetPwd(SysUser user) {
        int successCount = userMapper.updateUser(user);
        // 强制该用户退出登录
        Collection<String> keys = redisService.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
        for (String key : keys) {
            LoginUser onlineUser = redisService.getCacheObject(key);
            if (Objects.nonNull(onlineUser) && Objects.nonNull(onlineUser.getUserid())
                    && onlineUser.getUserid().longValue() == user.getUserId().longValue()) {
                redisService.deleteObject(key);
            }
        }
        return successCount;
    }

    /**
     * 修改用户基本信息
     *
     * @param user 用户信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateUserProfile(SysUser user) {
        if (StrUtils.isNotEmpty(user.getNickName())) {
            userMapper.updateReTableNickName(user.getUserId(), user.getNickName());
        }
        return userMapper.updateUser(user);
    }

    /**
     * 重置用户密码
     *
     * @param userName 用户名
     * @param password 密码
     * @return 结果
     */
    @Override
    public int resetUserPwd(String userName, String password) {
        return userMapper.resetUserPwd(userName, password);
    }

    /**
     * 新增用户角色信息
     *
     * @param user 用户对象
     */
    public void insertUserRole(SysUser user) {
        this.insertUserRole(user.getUserId(), user.getRoleIds(), user.getTenantId());
    }

    /**
     * 新增用户岗位信息
     *
     * @param user 用户对象
     */
    public void insertUserPost(SysUser user) {
        Long[] posts = user.getPostIds();
        if (StrUtils.isNotEmpty(posts)) {
            // 新增用户与岗位管理
            List<SysUserPost> list = new ArrayList<SysUserPost>();
            for (Long postId : posts) {
                SysUserPost up = new SysUserPost();
                up.setUserId(user.getUserId());
                up.setPostId(postId);
                up.setTenantId(user.getTenantId());
                list.add(up);
            }
            userPostMapper.batchUserPost(list);
        }
    }

    /**
     * 新增用户角色信息
     *
     * @param userId  用户ID
     * @param roleIds 角色组
     */
    @TemporaryIgnoreTables
    public void insertUserRole(Long userId, Long[] roleIds, Long tenantId) {

        // 通过角色id获取角色租户Id
        if (StrUtils.isNotEmpty(roleIds)) {

            // 通过角色id获取对应的租户Id
            List<SysRole> sysRoleList = new ArrayList<>();
            if (1 == SecurityUtils.getTenantType()) {
                SecurityUtils.setTemporaryIgnoreTables(Collections.singletonList("sys_role"));
                LambdaQueryWrapper<SysRole> sysRoleWrapper = new LambdaQueryWrapper<>();
                sysRoleWrapper.eq(SysRole::getDelFlag, "0");
                sysRoleWrapper.in(SysRole::getRoleId, roleIds);
                sysRoleList = roleMapper.selectList(sysRoleWrapper);
            }

            // 新增用户与角色管理
            List<SysUserRole> list = new ArrayList<>();
            for (Long roleId : roleIds) {
                SysUserRole ur = new SysUserRole();
                ur.setUserId(userId);
                ur.setRoleId(roleId);
                Optional<SysRole> sysRoleOptional = sysRoleList.stream().filter(sysRole -> sysRole.getRoleId().longValue() == roleId.longValue()).findFirst();
                ur.setTenantId(sysRoleOptional.isPresent() ? sysRoleOptional.get().getTenantId() : tenantId);
                list.add(ur);
            }

            userRoleMapper.batchUserRoleByTenantIds(list);
        }
    }

    /**
     * 通过用户ID删除用户
     *
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserAccountById(Long userId) {
        // 删除用户与角色关联
        userRoleMapper.deleteUserRoleByUserId(userId);
        return userMapper.clearUserAccountInfo(userId);
    }

    /**
     * 通过用户ID删除用户
     *
     * @param userId 用户ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserById(Long userId) {
        // 删除用户与角色关联
        userRoleMapper.deleteUserRoleByUserId(userId);
        // 删除用户与岗位表
        userPostMapper.deleteUserPostByUserId(userId);
        return userMapper.deleteUserById(userId);
    }

    /**
     * 批量删除用户信息
     *
     * @param userIds 需要删除的用户ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteUserByIds(Long[] userIds) {
        for (Long userId : userIds) {
            checkUserAllowed(new SysUser(userId));
            checkUserDataScope(userId);
        }
        // 删除用户与角色关联
        userRoleMapper.deleteUserRole(userIds);
        // 删除用户与岗位关联
        userPostMapper.deleteUserPost(userIds);
        // 删除用户与班级关联
        reClassUserMapper.deleteUserClass(userIds);
        return userMapper.deleteUserByIds(userIds);
    }

    /**
     * 导入用户数据
     *
     * @param userList        用户数据列表
     * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据
     * @param operName        操作用户
     * @return 结果
     */
    @Override
    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName) {
        if (StrUtils.isNull(userList) || userList.size() == 0) {
            throw new ServiceException("导入用户数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder failureMsg = new StringBuilder();
        String password = configService.selectConfigByKey("sys.user.initPassword");
        for (SysUser user : userList) {
            try {
                // 验证是否存在这个用户
                SysUser u = userMapper.selectUserByUserName(user.getUserName());
                if (StrUtils.isNull(u)) {
                    BeanValidators.validateWithException(validator, user);
                    user.setPassword(SecurityUtils.encryptPassword(password));
                    user.setCreateBy(operName);
                    userMapper.insert(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
                } else if (isUpdateSupport) {
                    BeanValidators.validateWithException(validator, user);
                    checkUserAllowed(u);
                    checkUserDataScope(u.getUserId());
                    user.setUserId(u.getUserId());
                    user.setUpdateBy(operName);
                    userMapper.updateUser(user);
                    successNum++;
                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
        }
        return successMsg.toString();
    }

    @Override
    public List<SysUser> selectUserAndRoleList(String roleKey) {
        return userMapper.selectUserAndRoleList(roleKey);
    }

    @Override
    public void checkUserAccount(SysUser user) {
        SecurityUtils.setTemporaryIgnoreTables(Collections.singletonList("sys_user"));
        LambdaQueryWrapper<SysUser> sysUserWrapper = new LambdaQueryWrapper<>();
        sysUserWrapper.eq(SysUser::getDelFlag, ConstantUtils.IS_DELETED_0);
        sysUserWrapper.eq(SysUser::getUserAccount, user.getUserAccount());
        sysUserWrapper.ne(TenantEntity::getTenantId, SecurityUtils.getTenantId());
        List<SysUser> sysUserList = userMapper.selectList(sysUserWrapper);

        // 判断其他园是否有账号且有账号状态为启用
        if (com.alibaba.nacos.common.utils.CollectionUtils.isNotEmpty(sysUserList)) {
            sysUserList.forEach(sysUser -> {
                if (ConstantUtils.ACCOUNT_STATUS_0.equals(sysUser.getAccountStatus())) {
                    throw new ServiceException("该手机号已在其他园开通且为启用状态，请联系平台客服处理，或更换教职工手机号后再试");
                }
            });
        }

        SecurityUtils.removeTemporaryIgnoreTables(Collections.singletonList("sys_user"));
    }


    /**
     * 根据手机号查询
     *
     * @param account
     * @return
     */
    @Override
    public SysUser selectUserByPhone(String account) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getPhonenumber, account)
                .eq(SysUser::getDelFlag, "0");
        return userMapper.selectOne(wrapper);
    }


    public SysUser selectByOpenId(String wxCode) {
        String openid = fetchOpenId(wxCode);
        SysWechatUser wechatUser = getWechatUser(openid);
        if (wechatUser == null) {
            String accessToken = fetchAccessToken();
            SysUser sysUser = fetchUserInfo(accessToken, openid);
            String phonenumber=fetchPhoneNumber(accessToken, wxCode);
            sysUser.setDelFlag(ConstantUtils.IS_DELETED_0);
            sysUser.setUserName(phonenumber);
            sysUser.setNickName(phonenumber);
            sysUser.setCreateById(SecurityUtils.getUserId());
            sysUser.setCreateTime(DateUtils.getNowDate());
            sysUser.setUserStatus("0");
            sysUser.setAccountStatus(ConstantUtils.ACCOUNT_STATUS_2);
            sysUser.setTenantId(SecurityUtils.getTenantId());
            sysUser.setVerifyStatus(0);
            sysUser.setSourceType(2);
            //默认密码采用随机生成
            String randomPassword = SecurityUtils.randomPassword(6);//随机密码6位
            String password = SecurityUtils.encryptPassword(randomPassword);
            sysUser.setPassword(password);
            sysUser.setUserAccount(sysUser.getPhonenumber());
            sysUser.setAccountDate(new Date());
            userMapper.insert(sysUser);
            //创建教职工账号
            SysTeachStaff sysTeachStaff = new SysTeachStaff();
            sysTeachStaff.setUserId(sysUser.getUserId());
            sysTeachStaff.setUserName(sysUser.getPhonenumber());
            sysTeachStaff.setPhonenumber(sysUser.getPhonenumber());
            sysTeachStaffMapper.insert(sysTeachStaff);

            SysWechatUser newWechatUser = new SysWechatUser();
            newWechatUser.setUserId(sysUser.getUserId());
            newWechatUser.setOpenId(openid);
            sysWechatUserMapper.insert(newWechatUser);

            return sysUser;
        }

        return userMapper.selectById(wechatUser.getUserId());
    }

    private String fetchOpenId(String wxCode) {
        String api = String.format("%s?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                accessToken, appId, secret, wxCode);

        Map<String, Object> response = restTemplate.getForObject(api, Map.class);
        if (response != null && response.containsKey("openid")) {
            return (String) response.get("openid");
        }
        throw new ServiceException("微信登录失败");
    }

    private SysWechatUser getWechatUser(String openid) {
        LambdaQueryWrapper<SysWechatUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysWechatUser::getOpenId, openid);
        return sysWechatUserMapper.selectOne(wrapper);
    }

    private String fetchAccessToken() {
        String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s",
                accessToken, appId, secret);

        Map<String, Object> response = restTemplate.getForObject(url, Map.class);
        if (response != null && response.containsKey("access_token")) {
            return (String) response.get("access_token");
        }
        throw new ServiceException("获取accessToken失败");
    }

    private SysUser fetchUserInfo(String accessToken, String openid) {
        String url = String.format("%s?access_token=%s&openid=%s", userInfoUrl, accessToken, openid);

        Map<String, Object> response = restTemplate.getForObject(url, Map.class);
        if (response != null) {
            SysUser user = new SysUser();
            user.setNickName((String) response.get("nickname"));
            user.setSex((String) response.get("sex"));
            user.setAvatar((String) response.get("headimgurl"));
            return user;
        }
        throw new ServiceException("获取用户信息失败");
    }

    private String fetchPhoneNumber(String accessToken, String wxCode) {
        String url = String.format("%s?access_token=%s", phoneNumber, accessToken);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("code", wxCode);

        HttpEntity<Map<String, String>> request = new HttpEntity<>(requestBody, headers);
        ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);

        if (response.getStatusCode() == HttpStatus.OK) {
            return extractPhoneNumber(response.getBody());
        } else {
            throw new RuntimeException("Error fetching phone number: " + response.getStatusCode());
        }
    }

    private String extractPhoneNumber(String responseBody) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode rootNode = objectMapper.readTree(responseBody);
            return rootNode.path("phone_info").path("purePhoneNumber").asText();
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Error parsing phone number response", e);
        }
    }

    /**
     * 获取用户昵称
     */
    @Override
    public List<String> selectByUserIdS(List<Long> userIds) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(SysUser::getUserId, userIds);
        List<SysUser> users = userMapper.selectList(wrapper);
        return users.stream().map(SysUser::getNickName).collect(Collectors.toList());
    }
}
