package com.ruoyi.framework.web.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.Header;
import cn.hutool.http.useragent.UserAgentUtil;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.constant.JustAuthConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.exception.user.CaptchaException;
import com.ruoyi.common.exception.user.CaptchaExpireException;
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.system.domain.SysAuthUser;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysUserService;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * 登录校验方法
 * 
 * @author ruoyi
 */
@Component
@Slf4j
public class SysAuthService
{

    @Autowired
    private RedisCache redisCache;
    
    @Autowired
    private ISysUserService userService;


    @Autowired
    private ISysConfigService configService;

    /**
     * 第三方回调登录
     * @param authUser
     * @return
     */
    public AjaxResult callbackLogin(AuthUser authUser){
        if (StringUtils.isNull(authUser)){
            throw new ServiceException("登录异常！请刷新后尝试");
        }
        Long userId = userService.selectUserIdByUuid(authUser.getUuid(), authUser.getSource());
        if (null == userId || userId == 0L){
            String authId = IdUtil.simpleUUID();
            redisCache.setCacheObject(JustAuthConstants.JUST_AUTH_CACHE_KEY+authId, copyBean(authUser),10, TimeUnit.MINUTES);
            return AjaxResult.error(HttpStatus.NOT_USER,"用户未绑定！请进行绑定").put("authId",authId);
        }
        AjaxResult ajax = AjaxResult.success();
        ajax.put(Constants.TOKEN, login(userId));
        return ajax;
    }


    /**
     * 第三方授权登录
     * @param userId
     * @return
     */
    public String login(Long userId)
    {
        // 用户验证
        SysUser user = null;
        try
        {
            user = userService.selectUserById(userId);
            if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
            {
                log.info("登录用户：{} 已被删除.", user.getUserName());
                throw new ServiceException("对不起，您的账号：" + user.getUserName() + " 已被删除");
            }
            else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
            {
                log.info("登录用户：{} 已被停用.", user.getUserName());
                throw new ServiceException("对不起，您的账号：" + user.getUserName() + " 已停用");
            }
            UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader(Header.USER_AGENT.getValue()));
            cn.hutool.http.useragent.UserAgent huUserAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader(Header.USER_AGENT.getValue()));
            //区分手机与pc 同端互斥
            StpUtil.login(user.getUserId(), huUserAgent.isMobile()?"PC":"APP");
            LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, userAgent);
            StpUtil.getSession().set(StpUtil.getTokenValue(),loginUser);
        }
        catch (Exception e)
        {
            if (e instanceof UserPasswordNotMatchException)
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            }
            else
            {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        recordLoginInfo(user.getUserId());
        // 生成token
        return StpUtil.getTokenValue();
    }

    /**
     * 校验验证码
     *
     * @param username 用户名
     * @param code 验证码
     * @param uuid 唯一标识
     * @return 结果
     */
    public void validateCaptcha(String username, String code, String uuid)
    {
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
        String captcha = redisCache.getCacheObject(verifyKey);
        redisCache.deleteObject(verifyKey);
        if (captcha == null)
        {
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha))
        {
            throw new CaptchaException();
        }
    }
    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId)
    {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr());
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }

    /**
     * 绑定第三方登录
     * @param authId
     * @param userId
     */
    public void bindUser(String authId,Long userId) throws ServiceException{
        SysAuthUser sysAuthUser = redisCache.getCacheObject(JustAuthConstants.JUST_AUTH_CACHE_KEY+authId);
        sysAuthUser.setUserId(userId);
        userService.bindSysUser(sysAuthUser);
    }

    /**
     * 复制第三方数据
     * @param authUser
     * @return
     */
    private SysAuthUser copyBean(AuthUser authUser){
        if (StringUtils.isNull(authUser)){
            return new SysAuthUser();
        }
        SysAuthUser sysAuthUser = new SysAuthUser();
        sysAuthUser.setAvatar(authUser.getAvatar());
        sysAuthUser.setUserName(authUser.getUsername());
        sysAuthUser.setEmail(authUser.getEmail());
        sysAuthUser.setNickName(authUser.getNickname());
        sysAuthUser.setSource(authUser.getSource());
        sysAuthUser.setUuid(authUser.getUuid());
        return sysAuthUser;
    }
}
