package cn.qinys.platform.upms.api.service.impl;

import cn.qinys.platform.base.exceptions.BizException;
import cn.qinys.platform.base.redis.RedisKeyEnum;
import cn.qinys.platform.base.security.utils.CurrentUtils;
import cn.qinys.platform.base.service.AbstractLoginService;
import cn.qinys.platform.base.utils.EncodeUtils;
import cn.qinys.platform.base.utils.PasswordUtils;
import cn.qinys.platform.base.utils.RandomUtils;
import cn.qinys.platform.base.utils.RedisUtils;
import cn.qinys.platform.base.vo.LoginUserInfo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import cn.qinys.platform.entity.upms.SystemSmsLog;
import cn.qinys.platform.entity.upms.UpmsRole;
import cn.qinys.platform.entity.upms.UpmsUser;
import cn.qinys.platform.entity.upms.UpmsUserRole;
import cn.qinys.platform.upms.api.mapper.SystemSmsLogMapper;
import cn.qinys.platform.upms.api.mapper.UpmsRoleMapper;
import cn.qinys.platform.upms.api.mapper.UpmsUserMapper;
import cn.qinys.platform.upms.api.mapper.UpmsUserRoleMapper;
import cn.qinys.platform.upms.api.req.AdminTokenReq;
import cn.qinys.platform.upms.api.req.CurrentUserUpdatePwdReq;
import cn.qinys.platform.upms.api.req.LoginSmsReq;
import cn.qinys.platform.upms.api.req.UserResetPasswordReq;
import cn.qinys.platform.upms.api.resp.AdminTokenResp;
import cn.qinys.platform.upms.api.service.ILoginService;
import cn.qinys.platform.upms.api.service.IRoleService;
import cn.qinys.platform.upms.api.service.IUserService;
import cn.qinys.platform.upms.constants.UpmsConstants;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * Description:
 *
 * @author tanlie
 * Date: 2024/2/5 9:43
 */
@Slf4j
@Service
@AllArgsConstructor
public class LoginServiceImpl extends AbstractLoginService implements ILoginService {
    private final RedisUtils redisUtils;
    private final UpmsUserMapper userMapper;
    private final PasswordEncoder passwordEncoder;
    private final UpmsRoleMapper roleMapper;
    private final UpmsUserRoleMapper upmsUserRoleMapper;
    private final IRoleService roleService;
    private final SystemSmsLogMapper smsLogMapper;
    private final PasswordUtils passwordUtils;
    private final IUserService userService;

    @Async
    @Override
    public void sendSmsCode(LoginSmsReq req) {
        // 短信发送逻辑
        String key = RedisKeyEnum.CAPTCHA.getCode() + req.getCaptchaKey();
        String captchaText = (String) redisUtils.get(key);
        if (!req.getCaptchaCode().equalsIgnoreCase(captchaText)) {
            throw new BizException("验证码不正确");
        }
        String username = EncodeUtils.decodeAes(req.getUsername());
        QueryWrapper<UpmsUser> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        wrapper.last("LIMIT 1");
        UpmsUser user = userMapper.selectOne(wrapper);
        if (user == null) {
            this.setFailCount(username);
            throw new BizException("用户不存在");
        }
        // 密码不正确也不发短信
       /* String rawPassword = EncodeUtils.decodeAes(req.getPassword());
        if (!passwordEncoder.matches(rawPassword, user.getPassword())) {
            this.setFailCount(username);
            throw new Biz500Exception("密码不正确");
        }*/
        if (user.getLocked().equals("1")) {
            this.setFailCount(username);
            throw new BizException("账号已失效，请联系管理员");
        }

        String code = RandomUtils.getNumRandom(6);
        String content = "尊敬的用户：您本次的验证码为：" + code + "，有效期为5分钟，请不要向他人泄露。";

        // TODO do something 记录短信发送到日志
        SystemSmsLog smsLog = new SystemSmsLog();
        smsLog.setMobile(user.getMobile());
        smsLog.setContent(content);
        smsLog.setResult("");
        smsLog.setTenantId(user.getTenantId());
        smsLog.setCreateTime(LocalDateTime.now());
        smsLog.setUpdateTime(LocalDateTime.now());
        smsLogMapper.insert(smsLog);
    }

    @Override
    public AdminTokenResp login(AdminTokenReq req) {
        // 校验验证码
        String codeKey = RedisKeyEnum.CAPTCHA.getCode() + req.getCaptchaKey();
        String code = (String) redisUtils.get(codeKey);
        if (!StringUtils.hasLength(code)) {
            throw new BizException("图片验证码已过期");
        }
        if (!code.equalsIgnoreCase(req.getCaptchaCode())) {
            throw new BizException("图片验证码不正确");
        }
        // 校验短信验证码
        String username = EncodeUtils.decodeAes(req.getUsername());
        this.checkFailCount(username);
        QueryWrapper<UpmsUser> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        wrapper.last("LIMIT 1");
        UpmsUser user = userMapper.selectOne(wrapper);
        // 用户不存
        if (user == null) {
            this.setFailCount(username);
            throw new BizException("用户不存在");
        }

        // 密码不正确
       /* String rawPassword = EncodeUtils.decodeAes(req.getPassword());
        if (!passwordEncoder.matches(rawPassword, user.getPassword())) {
            this.setFailCount(username);
            throw new Biz500Exception("密码不正确");
        }*/
        if ("1".equalsIgnoreCase(user.getLocked())) {
            this.setFailCount(username);
            throw new BizException("账号已被锁定");
        }
        user.setLoginCount(user.getLoginCount() + 1);
        user.setLastLoginTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());
        userMapper.updateById(user);

        UpmsRole activeRole = this.getLoginRole(user.getId());
        List<String> permissionCodes = roleService.getPermissionCodes(activeRole.getId(),activeRole.getSuperAdmin());
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        LoginUserInfo userInfo = new LoginUserInfo();
        userInfo.setId(user.getId());
        userInfo.setWxId(null);
        userInfo.setMobile(user.getMobile());
        userInfo.setUsername(user.getUsername());
        userInfo.setLoginRoleId(activeRole.getId());
        userInfo.setLoginRoleName(activeRole.getRoleCnName());
        userInfo.setPermissionCodes(permissionCodes);
        userInfo.setTenantId(user.getTenantId());
        userInfo.setSuperAdmin(activeRole.getSuperAdmin());
        this.setLoginUserInfo(userInfo, token);    // 登录后放入缓存的信息
        this.kicKOut(username); //踢人下线
        this.recordToken(username, token); // 记录token
        // 返回前端
        AdminTokenResp resp = new AdminTokenResp();
        resp.setToken(token);
        resp.setTtl(RedisKeyEnum.CURRENT_USER.getExpireTime());
        resp.setPermissionCodes(permissionCodes);
        resp.setUserName(username);
        resp.setMobile(userInfo.getMobile());
        return resp;
    }

    @Override
    public AdminTokenResp refreshToken() {
        LoginUserInfo userInfo = CurrentUtils.getCurrentUserInfo();
        String token = CurrentUtils.getToken();
        this.setLoginUserInfo(userInfo, token);    // 登录后放入缓存的信息
        this.recordToken(userInfo.getUsername(), token); // 记录token
        // 返回前端
        AdminTokenResp resp = new AdminTokenResp();
        resp.setToken(token);
        resp.setTtl(RedisKeyEnum.CURRENT_USER.getExpireTime());
        resp.setPermissionCodes(userInfo.getPermissionCodes());
        resp.setUserName(userInfo.getUsername());
        return resp;
    }

    @Override
    public void logout() {
        String username = CurrentUtils.getCurrentUsername();
        // 清除用户信息缓存
        redisUtils.delete(UpmsConstants.RedisKey.UPMS_USER_INFO.getCode() + CurrentUtils.getCurrentUserId());
        // 清除token
        this.kicKOut(username);

    }

    @Override
    public void updatePassword(CurrentUserUpdatePwdReq req) {
        if (!req.getNewPwd().equalsIgnoreCase(req.getAgnPwd())) {
            throw new BizException("两次密码不一致");
        }
        String password = EncodeUtils.decodeAes(req.getNewPwd());
        boolean res = passwordUtils.checkPassword(password);
        if (!res) {
            throw new BizException("密码格式不正确");
        }
        UserResetPasswordReq reset = new UserResetPasswordReq();
        reset.setPassword(password);
        reset.setId(CurrentUtils.getCurrentUserId());
        userService.resetPassword(reset);
    }

    private UpmsRole getLoginRole(String userId) {
        UpmsRole role = roleMapper.selectActiveRole(userId);
        if (role != null) {
            return role;
        }
        // 如果没有默认角色，选其中一条
        QueryWrapper<UpmsUserRole> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        wrapper.orderByAsc("id");
        wrapper.last("LIMIT 1");
        UpmsUserRole userRole = upmsUserRoleMapper.selectOne(wrapper);
        userRole.setActive("1");
        upmsUserRoleMapper.updateById(userRole);
        return roleMapper.selectActiveRole(userId);
    }
}
