package com.ningdatech.carapi.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.exception.BaseUncheckedException;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.exception.code.ExceptionCode;
import com.ningdatech.cache.repository.CachePlusOps;
import com.ningdatech.carapi.driver.constant.UserCanLoginEnum;
import com.ningdatech.carapi.sys.entity.UserRole;
import com.ningdatech.carapi.sys.entity.dto.UserSaveDTO;
import com.ningdatech.carapi.sys.entity.dto.UserUpdateDTO;
import com.ningdatech.carapi.sys.helper.UserCacheHelper;
import com.ningdatech.carapi.sys.service.UserRoleService;
import com.ningdatech.carapi.sys.utils.AuthCacheKeyUtils;
import com.ningdatech.carapi.user.entity.NdUserAuth;
import com.ningdatech.carapi.user.entity.NdUserInfo;
import com.ningdatech.carapi.user.mapper.NdUserInfoMapper;
import com.ningdatech.carapi.user.security.auth.constant.AuthTypeEnum;
import com.ningdatech.carapi.user.service.INdUserAuthService;
import com.ningdatech.carapi.user.service.INdUserInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author LiuXinXin
 * @since 2022-09-30
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class NdUserInfoServiceImpl extends ServiceImpl<NdUserInfoMapper, NdUserInfo> implements INdUserInfoService {
    private final CachePlusOps cachePlusOps;
    private final NdUserInfoMapper userMapper;
    private final INdUserAuthService ndUserAuthService;
    private final UserRoleService userRoleService;
    private final PasswordEncoder passwordEncoder;

    private final UserCacheHelper userCacheHelper;

    private static final String SUPER_ADMIN = "SUPER_ADMIN";

    /**
     * 删除用户时，需要级联删除跟角色相关的一切资源：
     * 1，角色本身
     * 2，角色-组织：
     * 3，角色-权限（菜单和按钮）：
     * 4，角色-用户：角色拥有的用户
     * 5，用户-权限：
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIdWithCache(List<Long> ids) {
        if (ids.isEmpty()) {
            return true;
        }
        // 用户
        boolean removeFlag = removeByIds(ids);

        //用户
        ids.forEach(userId -> {
            //删除关联表和缓存
            ndUserAuthService.remove(Wrappers.lambdaQuery(NdUserAuth.class).eq(NdUserAuth::getUserId,userId));
            userRoleService.remove(Wrappers.lambdaQuery(UserRole.class).eq(UserRole::getUserId,userId));
            cachePlusOps.del(AuthCacheKeyUtils.userResourceCacheKey(userId));
            userCacheHelper.refresh(userId);
        });

        return removeFlag;
    }


    /**
     * 保存用户
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(UserSaveDTO data, Long userId) {
        if(StrUtil.isNotBlank(data.getAccount()) && StrUtil.isNotBlank(data.getMobile())
                && check(data.getAccount(),data.getMobile())){
            throw new BaseUncheckedException(HttpStatus.HTTP_OK, "帐号{},或者手机号{} 输入有误或已经存在",
                    data.getAccount(),data.getMobile());
        }

        NdUserInfo user = BeanUtil.toBean(data, NdUserInfo.class);
        //创建人 最后修改人
        user.setCreateBy(userId);
        user.setUpdateBy(userId);
        user.setCanLogin(UserCanLoginEnum.CAN_LOGIN.getCode());
        if(save(user)){
            userCacheHelper.refresh(user.getId());
        }

        NdUserAuth userAuth = new NdUserAuth();
        userAuth.setUserId(user.getId());
        userAuth.setIdentifier(data.getAccount());
        userAuth.setCredential(passwordEncoder.encode(data.getPassword()));
        userAuth.setAuthType(AuthTypeEnum.ACCOUNT_PASSWORD.getKey());
        ndUserAuthService.save(userAuth);

        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(data.getRole());
        userRoleService.save(userRole);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(UserUpdateDTO data, Long userId) {
        NdUserInfo userOld = userMapper.selectById(data.getId());
        if(Objects.isNull(userOld)){
            throw new BaseUncheckedException(HttpStatus.HTTP_OK,String.format("修改用户%d 为空",data.getId()));
        }

        if(StringUtils.isNotBlank(data.getAccount())){
            Assert.isFalse(checkAccount(data.getAccount(),userOld.getId()), "帐号{} 已经存在",data.getAccount());
        }

        if(StringUtils.isNotBlank(data.getMobile())){
            Assert.isFalse(checkMobile(data.getMobile(),userOld.getId()), "手机号{} 已经存在",data.getMobile());
        }

        NdUserInfo user = BeanUtil.toBean(data, NdUserInfo.class);
        //最后修改人
        user.setUpdateBy(userId);
        if(updateById(user)){
            userCacheHelper.refresh(userId);
        }

        if(StringUtils.isNotBlank(data.getAccount())
                || StringUtils.isNotBlank(data.getPassword())){
            NdUserAuth authOld = ndUserAuthService.getOne(Wrappers.lambdaQuery(NdUserAuth.class)
                    .eq(NdUserAuth::getUserId, user.getId()));
            if(Objects.isNull(authOld)){
                //去新增个auth
                if(StringUtils.isBlank(data.getAccount())
                        || StringUtils.isBlank(data.getPassword())){
                    throw new BizException(ExceptionCode.BASE_VALID_PARAM.getCode(),String.format("修改auth用户%d 号码密码必填",data.getId()));
                }
                NdUserAuth userAuth = new NdUserAuth();
                userAuth.setUserId(user.getId());
                userAuth.setIdentifier(data.getAccount());
                userAuth.setCredential(passwordEncoder.encode(data.getPassword()));
                userAuth.setAuthType(AuthTypeEnum.ACCOUNT_PASSWORD.getKey());
                ndUserAuthService.save(userAuth);
            }else{
                if(StringUtils.isNotBlank(data.getAccount())){
                    authOld.setIdentifier(data.getAccount());
                }
                if(StringUtils.isNotBlank(data.getPassword())){
                    authOld.setCredential(passwordEncoder.encode(data.getPassword()));
                }
                authOld.setAuthType(AuthTypeEnum.ACCOUNT_PASSWORD.getKey());
                ndUserAuthService.updateById(authOld);
            }
        }

        if(Objects.nonNull(data.getRole())){
            userRoleService.remove(Wrappers.lambdaQuery(UserRole.class)
                    .eq(UserRole::getUserId, user.getId()));
            UserRole userRole = new UserRole();
            userRole.setUserId(user.getId());
            userRole.setRoleId(data.getRole());
            userRoleService.save(userRole);
        }
    }

    @Override
    public Boolean check(String account,String mobile) {
        return ndUserAuthService.count(Wrappers.lambdaQuery(NdUserAuth.class).eq(NdUserAuth::getIdentifier, account)) > 0 ||
                super.count(Wrappers.lambdaQuery(NdUserInfo.class).eq(NdUserInfo::getMobile,mobile)) > 0;
    }

    private Boolean checkMobile(String mobile,Long id) {
        return super.count(Wrappers.lambdaQuery(NdUserInfo.class).ne(NdUserInfo::getId,id).eq(NdUserInfo::getMobile,mobile)) > 0;
    }
    private Boolean checkAccount(String account,Long id) {
        return ndUserAuthService.count(Wrappers.lambdaQuery(NdUserAuth.class).ne(NdUserAuth::getUserId,id)
                .eq(NdUserAuth::getIdentifier, account)) > 0;
    }
}
