package com.njzscloud.supervisory.user.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.mp.support.PageResult;
import com.njzscloud.common.security.support.MenuResource;
import com.njzscloud.common.security.support.UserDetail;
import com.njzscloud.common.security.util.EncryptUtil;
import com.njzscloud.common.security.util.SecurityUtil;
import com.njzscloud.supervisory.menu.service.SysMenuService;
import com.njzscloud.supervisory.role.pojo.RoleDetailResult;
import com.njzscloud.supervisory.role.pojo.SysRoleEntity;
import com.njzscloud.supervisory.role.service.SysRoleService;
import com.njzscloud.supervisory.user.contant.Gender;
import com.njzscloud.supervisory.user.mapper.SysUserMapper;
import com.njzscloud.supervisory.user.pojo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 用户信息表
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserService extends ServiceImpl<SysUserMapper, SysUserEntity> implements IService<SysUserEntity> {
    private final SysUserAccountService sysUserAccountService;
    private final SysRoleService sysRoleService;
    private final SysUserRoleService sysUserRoleService;
    private final SysMenuService sysMenuService;

    /**
     * 新增
     *
     * @param addUserParam 数据
     * @return boolean 结果; true-->成功、false-->失败
     */
    @Transactional(rollbackFor = Exception.class)
    public Long add(AddUserParam addUserParam) {
        AddUserAccountParam addUserAccountParam = addUserParam.getAccount();
        String username = addUserAccountParam.getUsername();
        String email = addUserAccountParam.getEmail();
        String phone = addUserAccountParam.getPhone();
        String wechatOpenid = addUserAccountParam.getWechatOpenid();
        String wechatUnionid = addUserAccountParam.getWechatUnionid();
        List<SysUserAccountEntity> oldSysUserList = sysUserAccountService.list(Wrappers.<SysUserAccountEntity>lambdaQuery()
                .eq(SysUserAccountEntity::getUsername, username)
                .or().eq(StrUtil.isNotBlank(email), SysUserAccountEntity::getEmail, email)
                .or().eq(StrUtil.isNotBlank(phone), SysUserAccountEntity::getPhone, phone)
                .or(StrUtil.isNotBlank(wechatOpenid) && StrUtil.isNotBlank(wechatUnionid), it -> it.eq(SysUserAccountEntity::getWechatOpenid, wechatOpenid).eq(SysUserAccountEntity::getWechatUnionid, wechatUnionid))
        );
        Assert.isTrue(oldSysUserList.stream().noneMatch(it -> username.equals(it.getUsername())), () -> Exceptions.exception("用户名【{}】已被使用", username));
        Assert.isTrue(StrUtil.isBlank(email) || oldSysUserList.stream().noneMatch(it -> email.equals(it.getEmail())), () -> Exceptions.exception("邮箱【{}】已被使用", email));
        Assert.isTrue(StrUtil.isBlank(phone) || oldSysUserList.stream().noneMatch(it -> phone.equals(it.getPhone())), () -> Exceptions.exception("手机号【{}】已被使用", phone));
        Assert.isTrue(StrUtil.isBlank(wechatOpenid) || StrUtil.isBlank(wechatUnionid) || oldSysUserList.stream().noneMatch(it -> wechatOpenid.equals(it.getWechatOpenid()) && wechatUnionid.equals(it.getWechatUnionid())), () -> Exceptions.exception("该微信账号已被使用"));

        SysUserEntity sysUserEntity = BeanUtil.copyProperties(addUserParam, SysUserEntity.class);
        if (StrUtil.isNotBlank(email)) sysUserEntity.setEmail(email);
        if (StrUtil.isNotBlank(phone)) sysUserEntity.setPhone(phone);
        this.save(sysUserEntity);

        Long userEntityId = sysUserEntity.getId();

        sysUserAccountService.add(addUserAccountParam.setUserId(userEntityId));

        // List<Long> roleIds = addUserParam.getRoleIds();
        List<SysRoleEntity> roles = addUserParam.getRoles();
        if (CollUtil.isEmpty(roles)) return userEntityId;

        List<Long> roleIds = roles.stream().map(SysRoleEntity::getId).collect(Collectors.toList());

        List<SysRoleEntity> sysRoleEntities = sysRoleService.listByIds(roleIds);
        Assert.isTrue(sysRoleEntities.size() == roleIds.size(), () -> Exceptions.exception("角色不存在"));

        sysUserRoleService.saveBatch(roleIds.stream().map(roleId -> new SysUserRoleEntity().setRoleId(roleId).setUserId(userEntityId)).collect(Collectors.toList()));

        return userEntityId;
    }

    /**
     * 修改
     *
     * @param userModifyParam 数据
     */
    public void modify(UserModifyParam userModifyParam) {
        Long id = userModifyParam.getId();
        SysUserEntity sysUserEntity = this.getById(id);
        Assert.notNull(sysUserEntity, "要修改的数据不存在");

        UserAccountModifyParam account = userModifyParam.getAccount();
        String username = account.getUsername();
        String email = account.getEmail();
        String phone = account.getPhone();
        String wechatOpenid = account.getWechatOpenid();
        String wechatUnionid = account.getWechatUnionid();

        List<SysUserAccountEntity> oldSysUserList = sysUserAccountService.list(Wrappers.<SysUserAccountEntity>lambdaQuery()
                .ne(SysUserAccountEntity::getUserId, id)
                .and(it1 -> it1
                        .eq(SysUserAccountEntity::getUsername, username)
                        .or().eq(StrUtil.isNotBlank(email), SysUserAccountEntity::getEmail, email)
                        .or().eq(StrUtil.isNotBlank(phone), SysUserAccountEntity::getPhone, phone)
                        .or(StrUtil.isNotBlank(wechatOpenid) && StrUtil.isNotBlank(wechatUnionid),
                                it -> it.eq(SysUserAccountEntity::getWechatOpenid, wechatOpenid)
                                        .eq(SysUserAccountEntity::getWechatUnionid, wechatUnionid))
                )
        );
        Assert.isTrue(oldSysUserList.stream().noneMatch(it -> username.equals(it.getUsername())), () -> Exceptions.exception("用户名【{}】已被使用", username));
        Assert.isTrue(StrUtil.isBlank(email) || oldSysUserList.stream().noneMatch(it -> email.equals(it.getEmail())), () -> Exceptions.exception("邮箱【{}】已被使用", email));
        Assert.isTrue(StrUtil.isBlank(phone) || oldSysUserList.stream().noneMatch(it -> phone.equals(it.getPhone())), () -> Exceptions.exception("手机号【{}】已被使用", phone));
        Assert.isTrue(StrUtil.isBlank(wechatOpenid) || StrUtil.isBlank(wechatUnionid) || oldSysUserList.stream().noneMatch(it -> wechatOpenid.equals(it.getWechatOpenid()) && wechatUnionid.equals(it.getWechatUnionid())), () -> Exceptions.exception("该微信账号已被使用"));

        sysUserEntity = BeanUtil.copyProperties(userModifyParam, SysUserEntity.class);
        if (StrUtil.isNotBlank(email)) sysUserEntity.setEmail(email);
        if (StrUtil.isNotBlank(phone)) sysUserEntity.setPhone(phone);
        this.updateById(sysUserEntity);

        sysUserAccountService.modify(account.setUserId(id));

        // List<Long> roleIds = userModifyParam.getRoleIds();
        List<SysRoleEntity> roles = userModifyParam.getRoles();

        if (CollUtil.isEmpty(roles)) return;

        List<Long> roleIds = roles.stream().map(SysRoleEntity::getId).collect(Collectors.toList());

        List<SysRoleEntity> sysRoleEntities = sysRoleService.listByIds(roleIds);
        Assert.isTrue(sysRoleEntities.size() == roleIds.size(), () -> Exceptions.exception("角色不存在"));

        sysUserRoleService.remove(Wrappers.<SysUserRoleEntity>lambdaQuery().eq(SysUserRoleEntity::getUserId, id));

        sysUserRoleService.saveBatch(roleIds.stream().map(roleId -> new SysUserRoleEntity().setRoleId(roleId).setUserId(id)).collect(Collectors.toList()));
    }

    /**
     * 删除
     *
     * @param ids Id
     */
    @Transactional(rollbackFor = Exception.class)
    public void del(List<Long> ids) {
        this.removeByIds(ids);
        sysUserAccountService.remove(Wrappers.<SysUserAccountEntity>lambdaQuery().in(SysUserAccountEntity::getUserId, ids));
        sysUserRoleService.delByUserIds(ids);
    }

    /**
     * 详情
     *
     * @param id Id
     * @return UserDetailResult 结果
     */
    public UserDetailResult detail(Long id) {
        SysUserEntity sysUserEntity = this.getById(id);
        Assert.notNull(sysUserEntity, "未查询到用户信息");
        UserDetailResult userDetailResult = BeanUtil.copyProperties(sysUserEntity, UserDetailResult.class);
        SysUserAccountEntity userAccountEntity = sysUserAccountService.getOne(Wrappers.<SysUserAccountEntity>lambdaQuery().eq(SysUserAccountEntity::getUserId, id));
        Assert.notNull(userAccountEntity, "未查询到用户信息");
        UserAccountDetailResult userAccountDetailResult = BeanUtil.copyProperties(userAccountEntity, UserAccountDetailResult.class);
        List<RoleDetailResult> roleDetailResults = sysUserRoleService.listRole(id);
        return userDetailResult
                .setTenantId(sysUserEntity.getTenantId())
                .setAccount(userAccountDetailResult)
                .setRoles(roleDetailResults);
    }

    /**
     * 分页查询
     *
     * @param page           分页参数
     * @param userQueryParam 筛选条件
     * @return PageResult&lt;UserDetailResult&gt; 分页结果
     */
    public PageResult<UserDetailResult> paging(IPage<UserDetailResult> page, UserQueryParam userQueryParam) {
        String nickname = userQueryParam.getNickname();
        Gender gender = userQueryParam.getGender();
        String email = userQueryParam.getEmail();
        String phone = userQueryParam.getPhone();
        String username = userQueryParam.getUsername();
        Boolean disabled = userQueryParam.getDisabled();
        QueryWrapper<UserDetailResult> ew = Wrappers.<UserDetailResult>query()
                .like(StrUtil.isNotBlank(nickname), "a.nickname", nickname)
                .eq(gender != null, "a.gender", gender)
                .like(StrUtil.isNotBlank(email), "a.email", email)
                .like(StrUtil.isNotBlank(phone), "a.phone", phone)
                .like(StrUtil.isNotBlank(username), "b.username", username)
                .eq(disabled != null, "b.disabled", disabled);
        return PageResult.of(baseMapper.paging(page, ew));
    }

    public UserDetail getUserInfo(String account) {
        return sysUserAccountService.getUserInfo(account);
    }

    public void modifyPasswd(ModifyPasswdParam modifyPasswdParam) {
        Long userId = SecurityUtil.loginUser().getUserId();
        SysUserAccountEntity accountEntity = sysUserAccountService.getOne(Wrappers.<SysUserAccountEntity>lambdaQuery().eq(SysUserAccountEntity::getUserId, userId));
        boolean matches = EncryptUtil.matches(modifyPasswdParam.getOldPasswd(), accountEntity.getSecret());
        Assert.isTrue(matches, () -> Exceptions.exception("密码错误"));
        String newPasswd = EncryptUtil.encrypt(modifyPasswdParam.getNewPasswd());

        Long id = accountEntity.getId();

        sysUserAccountService.updateById(new SysUserAccountEntity()
                .setId(id)
                .setSecret(newPasswd)
        );
    }

    /**
     * 用户注册
     *
     * @param userRegisterParam 参数
     */
    @Transactional(rollbackFor = Exception.class)
    public void register(UserRegisterParam userRegisterParam) {
        AddUserParam addUserParam = BeanUtil.copyProperties(userRegisterParam, AddUserParam.class);
        addUserParam.setAccount(BeanUtil.copyProperties(userRegisterParam.getAccount(), AddUserAccountParam.class));
        Long userId = this.add(addUserParam);

        UserRegisterParam.Company company = userRegisterParam.getCompany();
        Assert.notNull(company, "公司信息不能为空");

        List<UserRegisterParam.Scope> scopeList = company.getScopeList();
    }

    public MyResult my() {
        UserDetail userDetail = SecurityUtil.loginUser();
        Long userId = userDetail.getUserId();
        SysUserEntity sysUserEntity = this.getById(userId);
        List<MenuResource> menuResources = sysMenuService.listUserMenu(userId);
        return BeanUtil.copyProperties(sysUserEntity, MyResult.class)
                .setMenus(menuResources);
    }
}
