package com.xy.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xy.collections.list.JArrayList;
import com.xy.collections.list.JList;
import com.xy.collections.map.JHashMap;
import com.xy.collections.map.JMap;
import com.xy.dto.SysWorkUser.*;
import com.xy.entity.*;
import com.xy.mapper.*;
import com.xy.redis.RedisCache;
import com.xy.service.SysUserDeptService;
import com.xy.service.SysUserRoleService;
import com.xy.service.SysWorkUserService;
import com.xy.utils.Beans;
import com.xy.utils.R;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


/**
 * <p>
 * 业务用户信息表 服务实现类
 * </p>
 *
 * @author lijin
 * @since 2022-12-09
 */
@Api(value = "业务用户管理")
@RequiredArgsConstructor
@Service
public class SysWorkUserServiceImpl extends ServiceImpl<SysWorkUserMapper, SysWorkUser> implements SysWorkUserService {

    private final SysUserRoleService sysUserRoleService;

    private final SysUserDeptService sysUserDeptService;

    private final SysUserRoleMapper sysUserRoleMapper;

    private final SysUserDeptMapper sysUserDeptMapper;

    private final SysRoleMapper sysRoleMapper;

    private final SysDeptMapper sysDeptMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Long> register(AddDto addDto) {
        //校验
        long count = count(new LambdaQueryWrapper<SysWorkUser>()
                .eq(SysWorkUser::getAccount, addDto.getAccount())
                .or()
                .eq(SysWorkUser::getPhone, addDto.getPhone())
        );
        if (count > 0) {
            return R.fail("账号或手机已存在");
        }
        //新增业务用户
        SysWorkUser sysWorkUser = Beans.copy(SysWorkUser.class, addDto)
                .create(RedisCache.getLoginId(Long.class))
                .setPassword(SecureUtil.md5(addDto.getPassword()));
        save(sysWorkUser);
        List<Long> roleIds = addDto.getRoleIds();
        if (CollUtil.isNotEmpty(roleIds)) {
            List<SysUserRole> sysUserRoleList = roleIds.stream().map(roleId -> new SysUserRole()
                    .setRoleId(roleId).setWorkUserId(sysWorkUser.getId()).setSysId(addDto.getSysId())).collect(Collectors.toList());
            //保存用户角色绑定信息
            sysUserRoleService.saveBatch(sysUserRoleList);
        }

        List<Long> deptIds = addDto.getDeptIds();
        if (CollUtil.isNotEmpty(deptIds)) {
            //关联部门
            List<SysUserDept> sysUserDeptList = deptIds.stream().map(deptId -> new SysUserDept()
                    .setDeptId(deptId).setWorkUserId(sysWorkUser.getId()).setSysId(addDto.getSysId())).collect(Collectors.toList());
            //保存用户部门 绑定信息
            sysUserDeptService.saveBatch(sysUserDeptList);
        }
        return R.ok(sysWorkUser.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Boolean> update(UpdateDto updateDto) {
        //更新用户信息
        SysWorkUser sysWorkUser = Beans.copy(SysWorkUser.class, updateDto)
                .update(RedisCache.getLoginId(Long.class))
                .setPassword(StringUtils.isNotEmpty(updateDto.getPassword()) ? SecureUtil.md5(updateDto.getPassword()) : null);
        updateById(sysWorkUser);
        //更新角色信息
        List<Long> roleIds = updateDto.getRoleIds();
        if (CollUtil.isNotEmpty(roleIds)) {
            sysUserRoleService.remove(Wrappers.<SysUserRole>lambdaUpdate().eq(SysUserRole::getWorkUserId, sysWorkUser.getId())
                    .eq(SysUserRole::getSysId, updateDto.getSysId()));

            List<SysUserRole> sysUserRoleList = roleIds.stream().map(roleId -> new SysUserRole()
                    .setRoleId(roleId).setWorkUserId(sysWorkUser.getId()).setSysId(updateDto.getSysId())).collect(Collectors.toList());
            //保存用户角色绑定信息
            sysUserRoleService.saveBatch(sysUserRoleList);

        }
        //更新部门信息
        List<Long> deptIds = updateDto.getDeptIds();
        if (CollUtil.isNotEmpty(deptIds)) {
            sysUserDeptService.remove(Wrappers.<SysUserDept>lambdaUpdate()
                    .eq(SysUserDept::getWorkUserId, sysWorkUser.getId())
                    .eq(SysUserDept::getSysId, updateDto.getSysId()));

            List<SysUserDept> newSysUserDeptList = deptIds.stream().map(deptId -> new SysUserDept()
                    .setDeptId(deptId).setWorkUserId(sysWorkUser.getId()).setSysId(updateDto.getSysId())).collect(Collectors.toList());
            sysUserDeptService.saveBatch(newSysUserDeptList);

        }
        return R.ok(Boolean.TRUE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R del(DelDto delDto) {
        //删除用户角色
        sysUserRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getWorkUserId, delDto.getId()));
        //删除用户部门
        sysUserDeptMapper.delete(new LambdaQueryWrapper<SysUserDept>().in(SysUserDept::getWorkUserId, delDto.getId()));
        //删除用户
        removeBatchByIds(delDto.getId());
        return R.ok();
    }

    @Override
    public R<String> login(LoginDto loginDto) {
        SysWorkUser sysWorkUser;
        //手机短信登录
        if (!StringUtils.isEmpty(loginDto.getCode())) {
            //todo 验证短信
            if (false) {
                return R.fail("短信验证码错误");
            }
            sysWorkUser = getOne(new LambdaQueryWrapper<SysWorkUser>().eq(SysWorkUser::getPhone, loginDto.getLoginName()));
        } else {
            //账号、邮箱、手机、密码登录
            LambdaQueryWrapper<SysWorkUser> lambdaQueryWrapper = new LambdaQueryWrapper<SysWorkUser>()
                    .and(sysWorkUserLambdaQueryWrapper -> sysWorkUserLambdaQueryWrapper
                            .eq(SysWorkUser::getAccount, loginDto.getLoginName())
                            .or()
                            .eq(SysWorkUser::getEmail, loginDto.getLoginName())
                            .or()
                            .eq(SysWorkUser::getPhone, loginDto.getLoginName()))
                    .eq(SysWorkUser::getPassword, SecureUtil.md5(loginDto.getPassword()));
            sysWorkUser = getOne(lambdaQueryWrapper);
        }
        if (sysWorkUser == null) {
            return R.fail("登录名或密码错误");
        }
        if (!sysWorkUser.getStatus()) {
            return R.fail("账号已被封禁");
        }
        //生成token
        StpUtil.login(sysWorkUser.getId(), loginDto.getClientType());
        //更新登录信息
        SysWorkUser workUser = new SysWorkUser()
                .setId(sysWorkUser.getId())
                .setLastLoginId(loginDto.getLoginName())
                .setLastLoginTime(LocalDateTime.now())
                .setLoginNum(sysWorkUser.getLoginNum() + 1);
        updateById(workUser);
        //缓存权限相关到redis
        RedisCache.workCache(sysWorkUser.getId());
        return R.ok(StpUtil.getTokenValue());
    }

    @Override
    public R logout() {
        StpUtil.logoutByTokenValue(RedisCache.getToken());
        return R.ok();
    }

    @Override
    public R<List<SysWorkVo>> list(ListDto listDto) {
        //条件构造
        JoinLambdaWrapper<SysWorkUser> joinLambdaWrapper = new JoinLambdaWrapper<>(SysWorkUser.class)
                .in(SysWorkUser::getId, listDto.getId())
                .leftJoin(SysUserRole.class, SysUserRole::getWorkUserId, SysWorkUser::getId)
                .manyToManySelect(SysWorkVo::getRoleIds, Long.class, cb -> cb.add(SysUserRole::getRoleId))
                .end()
                .leftJoin(SysUserDept.class, SysUserDept::getWorkUserId, SysWorkUser::getId)
                .manyToManySelect(SysWorkVo::getDeptIds, Long.class, cb -> cb.add(SysUserDept::getDeptId))
                .end();
        //查询数据
        List<SysWorkVo> sysWorkVos = baseMapper.joinSelectList(joinLambdaWrapper, SysWorkVo.class);
        if (sysWorkVos.size() > 0) {
            //查询角色信息
            JList<List<Long>> roleIdss = new JArrayList<>(sysWorkVos).getProperty(SysWorkVo::getRoleIds);
            List<Long> roleIds = new ArrayList<>();
            roleIdss.forEach(longs -> roleIds.addAll(longs));
            JMap<Long, SysRole> sysRoleJMap = new JHashMap<>();
            if (roleIds.size() > 0) {
                List<SysRole> sysRoles = sysRoleMapper.selectList(new LambdaQueryWrapper<SysRole>().in(SysRole::getId, roleIds));
                sysRoleJMap = new JArrayList<>(sysRoles).toMap(SysRole::getId).cover();
            }
            //查询部门信息
            JList<List<Long>> deptIdss = new JArrayList<>(sysWorkVos).getProperty(SysWorkVo::getDeptIds);
            List<Long> deptIds = new ArrayList<>();
            deptIdss.forEach(longs -> deptIds.addAll(longs));
            JMap<Long, SysDept> sysDeptJMap = new JHashMap<>();
            if (deptIds.size() > 0) {
                List<SysDept> sysDepts = sysDeptMapper.selectList(new LambdaQueryWrapper<SysDept>().in(SysDept::getId, deptIds));
                sysDeptJMap = new JArrayList<>(sysDepts).toMap(SysDept::getId).cover();
            }
            //处理结果值
            for (SysWorkVo sysWorkVo : sysWorkVos) {
                List<Long> workVoRoleIds = sysWorkVo.getRoleIds();
                sysWorkVo.setRoleNames(new ArrayList<>());
                for (Long workVoRoleId : workVoRoleIds) {
                    SysRole sysRole = sysRoleJMap.get(workVoRoleId);
                    if (sysRole == null) {
                        break;
                    }
                    sysWorkVo.getRoleNames().add(sysRole.getName());
                }
                List<Long> workVoDeptIds = sysWorkVo.getDeptIds();
                sysWorkVo.setDeptNames(new ArrayList<>());
                for (Long workVoDeptId : workVoDeptIds) {
                    SysDept sysDept = sysDeptJMap.get(workVoDeptId);
                    if (sysDept == null) {
                        break;
                    }
                    sysWorkVo.getDeptNames().add(sysDept.getName());
                }
            }
        }
        sysWorkVos.forEach(sysWorkVo -> sysWorkVo.setPassword(null));
        return R.ok(sysWorkVos);
    }
}
