package com.gitee.sop.admin.service.sys.login;

import com.gitee.sop.admin.common.config.Configs;
import com.gitee.sop.admin.common.enums.ConfigKeyEnum;
import com.gitee.sop.admin.common.enums.StatusEnum;
import com.gitee.sop.admin.common.exception.BizException;
import com.gitee.sop.admin.common.manager.UserCacheManager;
import com.gitee.sop.admin.common.util.CopyUtil;
import com.gitee.sop.admin.common.util.DateUtil;
import com.gitee.sop.admin.common.util.GenerateUtil;
import com.gitee.sop.admin.common.util.JwtUtil;
import com.gitee.sop.admin.dao.entity.SysUser;
import com.gitee.sop.admin.service.sys.SysUserService;
import com.gitee.sop.admin.service.sys.UserPermissionService;
import com.gitee.sop.admin.service.sys.dto.UserPermissionDTO;
import com.gitee.sop.admin.service.sys.login.dto.LoginDTO;
import com.gitee.sop.admin.service.sys.login.dto.LoginForm;
import com.gitee.sop.admin.service.sys.login.dto.LoginResult;
import com.gitee.sop.admin.service.sys.login.dto.LoginUser;
import com.gitee.sop.admin.service.sys.login.enums.RegTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author 六如
 */
@Service
@Slf4j
public class LoginService {

    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private UserCacheManager userCacheManager;
    @Autowired
    private UserPermissionService userPermissionService;


    public LoginUser login(LoginDTO loginDTO) {
        String username = loginDTO.getUsername();
        String password = loginDTO.getPassword();
        RegTypeEnum regType = loginDTO.getRegType();
        SysUser userInfo;
        switch (regType) {
            case FORM:
                throw new UnsupportedOperationException("第三方登录暂未支持");
            case LDAP:
                // LDAP登录
                throw new UnsupportedOperationException("LDAP登录登录暂未支持");
            default:
                // 默认注册账号登录
                userInfo = this.doDatabaseLogin(username, password);
        }
        LoginUser loginUser = buildLoginUser(userInfo);
        // 保存到缓存
        userCacheManager.saveUser(loginUser);
        return loginUser;
    }

    private LoginUser buildLoginUser(SysUser sysUser) {
        if (StatusEnum.of(sysUser.getStatus()) == StatusEnum.DISABLED) {
            throw new BizException("账号已禁用，请联系管理员");
        }
        // 登录成功
        LoginUser loginUser = CopyUtil.copyBean(sysUser, LoginUser::new);
        // 创建token
        String token = this.createToken(sysUser.getId());
        loginUser.setAccessToken(token);
        UserPermissionDTO userPermission = userPermissionService.getUserPermission(loginUser.getUserId());
        // 角色权限
        loginUser.setRoles(userPermission.getRoles());
        loginUser.setPermissions(userPermission.getPermissions());
        // 设置token过期时间
        String value = Configs.getValue(ConfigKeyEnum.JWT_TIMEOUT_DAYS);
        LocalDateTime expireDate = LocalDateTime.now().plusDays(NumberUtils.toInt(value));
        loginUser.setExpires(DateUtil.formatFrontDate(expireDate));
        return loginUser;
    }

    private String createToken(long userId) {
        Map<String, String> data = new HashMap<>(4);
        data.put("id", String.valueOf(userId));
        String value = Configs.getValue(ConfigKeyEnum.JWT_TIMEOUT_DAYS);
        return JwtUtil.createJwt(data, NumberUtils.toInt(value), getJwtSecret());
    }

    public static String getJwtSecret() {
        return Configs.getValue(ConfigKeyEnum.JWT_SECRET);
    }

    private SysUser doThirdPartyLogin(ThirdPartyLoginManager thirdPartyLoginManager, String username, String password) {
        LoginForm loginForm = new LoginForm();
        loginForm.setUsername(username);
        loginForm.setPassword(password);
        LoginResult loginResult;
        try {
            loginResult = thirdPartyLoginManager.login(loginForm);
        } catch (Exception e) {
            log.error("第三方登录失败", e);
            throw new BizException(e.getMessage());
        }

        SysUser userInfo = sysUserService.getByUsername(username);

        // 用户第一次登录则插入到user_info表
        if (userInfo == null) {
            userInfo = new SysUser();
            userInfo.setUsername(username);
            userInfo.setPassword(GenerateUtil.getUUID());
            userInfo.setNickname(loginResult.getNickname());
            userInfo.setAvatar("");
            userInfo.setStatus(StatusEnum.ENABLE.getValue());
            userInfo.setRegType(loginResult.getRegTypeEnum().getValue());
            userInfo.setEmail(loginResult.getEmail());
            sysUserService.save(userInfo);
        } else {
            String email = loginResult.getEmail();
            // 如果更改了邮箱
            if (StringUtils.hasText(email) && !Objects.equals(email, userInfo.getEmail())) {
                userInfo.setEmail(email);
                sysUserService.update(userInfo);
            }
        }
        return userInfo;
    }

    private SysUser doDatabaseLogin(String username, String password) {
        SysUser sysUser = sysUserService.getByUsername(username);
        Assert.notNull(sysUser, () -> "用户名密码不正确");
        String encodedPasswordDb = sysUser.getPassword();
        // 校验
        boolean flag = BCrypt.checkpw(password, encodedPasswordDb);
        Assert.isTrue(flag, () -> "用户名密码不正确");
        Assert.isTrue(Objects.equals(sysUser.getStatus(), StatusEnum.ENABLE.getValue()), () -> "用户已禁用");
        return sysUser;
    }

}
