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.metadata.IPage;
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.dto.SysWorkUser.*;
import com.xy.entity.SysUserDept;
import com.xy.entity.SysUserRole;
import com.xy.entity.SysWorkUser;
import com.xy.mapper.SysUserDeptMapper;
import com.xy.mapper.SysUserRoleMapper;
import com.xy.mapper.SysWorkUserMapper;
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.Emptys;
import com.xy.utils.PageBean;
import com.xy.utils.R;
import icu.mhb.mybatisplus.plugln.core.JoinLambdaWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

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

import static com.xy.utils.PlusBeans.toIPage;
import static com.xy.utils.PlusBeans.toPageBean;


/**
 * <p>
 * 业务用户信息表 服务实现类
 * </p>
 *
 * @author lijin
 * @since 2022-12-09
 */
@Api(tags = "业务用户管理")
@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;

    @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.logout(RedisCache.getLoginId(Long.class), StpUtil.getLoginDevice());
        return R.ok();
    }

    @ApiOperation("分页查询")
    @PostMapping("page")
    public R<PageBean<SysWorkVo>> page(@RequestBody PageDto pageDto) {
        //条件构造
        JoinLambdaWrapper<SysWorkUser> joinLambdaWrapper = new JoinLambdaWrapper<>(SysWorkUser.class)
                .eq(pageDto.getId() != null, SysWorkUser::getId, pageDto.getId())
                .like(StringUtils.isNotEmpty(pageDto.getAccount()), SysWorkUser::getAccount, pageDto.getAccount())
                .like(StringUtils.isNotEmpty(pageDto.getEmail()), SysWorkUser::getEmail, pageDto.getEmail())
                .like(StringUtils.isNotEmpty(pageDto.getPhone()), SysWorkUser::getPhone, pageDto.getPhone())
                .like(pageDto.getStatus() != null, SysWorkUser::getStatus, pageDto.getStatus())
                .ge(pageDto.getBeginCreateTime() != null, SysWorkUser::getCreateTime, pageDto.getBeginCreateTime())
                .le(pageDto.getEndCreateTime() != null, SysWorkUser::getCreateTime, pageDto.getEndCreateTime())
                .leftJoin(SysUserRole.class, SysUserRole::getWorkUserId, SysWorkUser::getId)
                .eq(pageDto.getRoleId() != null, SysUserRole::getRoleId, pageDto.getRoleId())
                .eq(pageDto.getSysId() != null, SysUserRole::getSysId, pageDto.getSysId())
                .manyToManySelect(SysWorkVo::getRoleIds, Long.class, cb -> cb.add(SysUserRole::getRoleId))
                .end()
                .leftJoin(SysUserDept.class, SysUserDept::getWorkUserId, SysWorkUser::getId)
                .eq(pageDto.getDeptId() != null, SysUserDept::getDeptId, pageDto.getDeptId())
                .manyToManySelect(SysWorkVo::getDeptIds, Long.class, cb -> cb.add(SysUserDept::getDeptId))
                .end();
        PageBean page = pageDto.getPage();
        if (!Emptys.check(page.getOrders())) {
            joinLambdaWrapper.orderByDesc(SysWorkUser::getCreateTime);
        }
        //数据鉴权
        boolean authByData = RedisCache.authByData(RedisCache.getSystemId(), RedisCache.getUri());
        if (!authByData) {
            joinLambdaWrapper.eq(SysWorkUser::getCreateUser, RedisCache.getLoginId(Long.class));
        }
        //查询数据
        IPage<SysWorkVo> sysWorkUserIPage = baseMapper.joinSelectPage(toIPage(page), joinLambdaWrapper, SysWorkVo.class);
        List<SysWorkVo> records = sysWorkUserIPage.getRecords();
        records.forEach(sysWorkVo -> sysWorkVo.setPassword(null));
        return R.ok(toPageBean(sysWorkUserIPage));
    }
}
