package com.ruoyi.cai.auth;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.cai.domain.*;
import com.ruoyi.cai.enums.CodeEnum;
import com.ruoyi.cai.enums.SystemConfigEnum;
import com.ruoyi.cai.executor.ExecutorConstant;
import com.ruoyi.cai.manager.CodeManager;
import com.ruoyi.cai.manager.LockManager;
import com.ruoyi.cai.manager.SystemConfigManager;
import com.ruoyi.cai.service.*;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.enums.UserType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.AddressUtils;
import com.ruoyi.system.service.SysLoginService;
import com.ruoyi.yunxin.Yunxin;
import com.ruoyi.yunxin.client.ImUserClient;
import com.ruoyi.yunxin.req.CreateUserReq;
import com.ruoyi.yunxin.req.UpdateTokenReq;
import com.ruoyi.yunxin.resp.YxCommonR;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class CaiLoginManager {

    @Autowired
    private UserService userService;
    @Autowired
    private SysLoginService sysLoginService;
    @Autowired
    private CodeManager codeManager;
    @Autowired
    private UserCodeGenService userCodeGenService;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private SystemConfigManager systemConfigManager;
    @Autowired
    private AccountService accountService;
    @Autowired
    private UserOnlineService userOnlineService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private UserInviteService userInviteService;
    @Autowired
    private UnionService unionService;
    @Autowired
    private UnionUserService unionUserService;
    @Autowired
    private Yunxin yunxin;
    @Resource
    private ImUserClient imUserClient;
    @Autowired
    private UserCountService userCountService;


    public String login(String username,String password){
        User user = userService.getByUsername(username);
        if(user == null){
            throw new ServiceException("用户不存在或密码错误");
        }
        if(user.getStatus() != 0){
            throw new ServiceException("用户已封禁，请联系客服");
        }
        if(!BCrypt.checkpw(password, user.getPassword())){
            throw new ServiceException("用户不存在或密码错误");
        }
        return login(user);
    }

    public String register(CaiRegisterUser caiUser) {
        User user = userService.getByUsername(caiUser.getUsername());
        if(user == null){
            throw new ServiceException("手机号已存在");
        }
        if(!caiUser.getPassword().equals(caiUser.getPasswordCheck())){
            throw new ServiceException("两次输入密码不一致，请检查");
        }
        boolean check = codeManager.check(CodeEnum.REGISTER, caiUser.getUsername(), caiUser.getCode());
        if(!check){
            throw new ServiceException("验证码错误");
        }
        // 加锁
        String lockKey = LockManager.getRegisterLockKey(caiUser.getUsername());
        RLock lock = redissonClient.getLock(lockKey);
        if(lock.isLocked()){
            throw new ServiceException("您点击太快了");
        }
        lock.lock(5, TimeUnit.SECONDS);
        try {
            CaiLoginManager bean = SpringUtil.getBean(CaiLoginManager.class);
            user = bean.registerUser(caiUser);
        }finally {
            lock.unlock();
        }
        if(user.getInviteId() != null){
            User finalUser = user;
            ExecutorConstant.COMMON_EXECUTOR.execute(() -> dealInviteId(finalUser));
        }
        return login(user);
    }



    public void dealInviteId(User user){
        Long inviteId = user.getInviteId();
        if(inviteId == null){
            return;
        }
        User inviteUser = userService.getById(inviteId);
        if(inviteUser == null){
            return;
        }
        String key = LockManager.getDealInviteLockKey(inviteId);
        RLock lock = redissonClient.getLock(key);
        if(!lock.isLocked()){
            log.warn("点击太快了，等一等，dealInviteId");
            return;
        }
        lock.lock(5,TimeUnit.SECONDS);
        try {
            UserInvite check = userInviteService.getByUserId(user.getId());
            if(check == null){
                UserInfo userInfo = userInfoService.getByUserId(user.getId());
                UserInvite userInvite = new UserInvite();
                userInvite.setUserId(user.getId());
                userInvite.setInviteId(user.getInviteId());
                userInvite.setVideoIncomeRate(userInfo.getVideoIncomeRate());
                userInvite.setGuardIncomeRate(userInfo.getGuardIncomeRate());
                userInvite.setGiftIncomeRate(userInfo.getGiftIncomeRate());
                userInvite.setPayIncomeRate(userInfo.getPayIncomeRate());
                if(inviteUser.getIsUnion() == 1){
                    BigDecimal unionOneRate = systemConfigManager.getSystemConfigOfBigDecimal(SystemConfigEnum.DEFAULT_UNION_ONE_INCOME_RATE);
                    BigDecimal videoIncome = NumberUtil.add(userInfo.getVideoIncomeRate(), unionOneRate);
                    userInvite.setVideoIncomeRate(videoIncome);
                }
                userInviteService.save(userInvite);
            }
            // 处理工会
            Union union = null; //
            if(inviteUser.getIsUnion() == 1){
                union = unionService.getByUserId(inviteUser.getId());
            } else {
                UnionUser unionUser = unionUserService.getByUserId(inviteUser.getId());
                if(unionUser != null){
                    union = unionService.getById(unionUser);
                }
            }
            if(union == null){
                log.info("邀请人没有工会，无法入会 inviteId={}",inviteId);
                return;
            }
            UnionUser checkUnionUser = unionUserService.getByUserId(user.getId());
            if(checkUnionUser != null){
                UnionUser unionUser = new UnionUser();
                unionUser.setUnionId(union.getId());
                unionUser.setUserId(user.getId());
                unionUser.setVideoDivide(systemConfigManager.getSystemConfigOfBigDecimal(SystemConfigEnum.DEFAULT_UNION_VIDEO_INCOME_RATE));
                unionUser.setGiftDivide(systemConfigManager.getSystemConfigOfBigDecimal(SystemConfigEnum.DEFAULT_UNION_VIDEO_INCOME_RATE));
                unionUser.setVipDivide(BigDecimal.ZERO);
                unionUser.setEnableRate(true);
                unionUserService.save(unionUser);
            }
        }finally {
            lock.unlock();
        }

    }


    public void recordLoginInfo(User user, String ip) {
        String address = AddressUtils.getRealAddressByIP(ip);
        UserInfo userInfo = userInfoService.getById(user.getId());
        UserInfo update = new UserInfo();
        update.setUserId(user.getId());
        update.setLoginCount(userInfo.getLoginCount()+1);
        update.setLastLoginIp(ip);
        update.setLastLoginTime(LocalDateTime.now());
        update.setLastLocation(address);
        userInfoService.updateById(update);
    }


    /**
     * 退出登录
     */
    public void logout() {
        try {
            LoginUser loginUser = LoginHelper.getLoginUser();
            sysLoginService.recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
        } catch (NotLoginException ignored) {
        } finally {
            try {
                StpUtil.logout();
            } catch (NotLoginException ignored) {
            }
        }
    }

    private String login(User user){
        LoginUser loginUser = new LoginUser();
        loginUser.setDeptId(null);
        loginUser.setDeptName(null);
        loginUser.setMenuPermission(Collections.emptySet());
        loginUser.setRolePermission(Collections.emptySet());
        loginUser.setUsername(user.getMobile());
        loginUser.setRoles(Collections.emptyList());
        loginUser.setRoleId(null);
        loginUser.setUserId(user.getId());
        loginUser.setUserType(UserType.APP_USER.getUserType());
        LoginHelper.login(loginUser);
        sysLoginService.recordLogininfor(loginUser.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        String clientIP = ServletUtils.getClientIP();
        ExecutorConstant.COMMON_EXECUTOR.execute(() -> recordLoginInfo(user,clientIP));
        return StpUtil.getTokenValue();
    }


    @Transactional(rollbackFor = Exception.class)
    public User registerUser(CaiRegisterUser user){
        String usercode = userCodeGenService.getCodeGen();
        User add = new User();
        add.setUsercode(usercode);
        add.setNickname("蜜瓜"+usercode);
        add.setType(0);
        add.setPassword(BCrypt.hashpw(user.getPassword()));
        add.setMobile(user.getUsername());
        add.setAvatar(null);
        add.setGender(user.getGender());
        add.setCity(user.getCity());
        add.setInviteId(user.getInviteId());
        add.setImToken(IdUtil.simpleUUID());
        userService.save(add);
        CreateUserReq req = new CreateUserReq();
        req.setAccid(add.getId()+"");
        req.setToken(add.getImToken());
        req.setName(add.getNickname());
        YxCommonR r = imUserClient.createUser(req);
        if(!r.isSuccess()){
            if(r.getCode() == 414){
                UpdateTokenReq req1 = new UpdateTokenReq();
                req1.setAccid(add.getId()+"");
                req1.setToken(add.getImToken());
                YxCommonR commonR = imUserClient.updateToken(req1);
                if(!commonR.isSuccess()){
                    log.error("刷新云token失败,{}", JSON.toJSONString(commonR));
                    throw new ServiceException("注册失败，云信异常");
                }
            }else{
                log.error("创建云信账号失败,{}", JSON.toJSONString(r));
                throw new ServiceException("注册失败，云信异常");
            }
        }
        String clientIP = ServletUtils.getClientIP();
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(add.getId());
        userInfo.setVideoIncomeRate(systemConfigManager.getSystemConfigOfBigDecimal(SystemConfigEnum.DEFAULT_VIDEO_INCOME_RATE));
        userInfo.setGuardIncomeRate(systemConfigManager.getSystemConfigOfBigDecimal(SystemConfigEnum.DEFAULT_GUARD_INCOME_RATE));
        userInfo.setGiftIncomeRate(systemConfigManager.getSystemConfigOfBigDecimal(SystemConfigEnum.DEFAULT_GIFT_INCOME_RATE));
        userInfo.setPayIncomeRate(systemConfigManager.getSystemConfigOfBigDecimal(SystemConfigEnum.DEFAULT_PAY_INCOME_RATE));
        userInfo.setLoginCount(1);
        userInfo.setLastLoginIp(clientIP);
        userInfo.setLastLoginTime(LocalDateTime.now());
        userInfo.setRegIp(clientIP);
        userInfo.setRegTime(LocalDateTime.now());
        userInfoService.save(userInfo);
        Account account = new Account();
        account.setUserId(add.getId());
        accountService.save(account);
        UserOnline userOnline = new UserOnline();
        userOnline.setUserId(add.getId());
        userOnlineService.save(userOnline);
        UserCount userCount = new UserCount();
        userCount.setUserId(add.getId());
        userCountService.save(userCount);
        return add;
    }


    public void resetPassword(ResetPasswordReq code) {
        User user = userService.getByUsername(code.getMobile());
        if(user == null){
            throw new ServiceException("账户不存在");
        }
        userService.resetPassword(code.getMobile(),code.getPassword());
    }
}
