package com.starry.admin.modules.system.service.impl;

import cn.hutool.core.convert.Convert;
import com.starry.admin.common.component.JwtToken;
import com.starry.admin.common.domain.LoginUser;
import com.starry.admin.common.exception.ServiceException;
import com.starry.admin.common.security.entity.JwtUser;
import com.starry.admin.manager.AsyncManager;
import com.starry.admin.manager.factory.AsyncFactory;
import com.starry.admin.modules.system.module.entity.SysTenantEntity;
import com.starry.admin.modules.system.module.entity.SysUserEntity;
import com.starry.admin.modules.system.service.*;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.constant.Constants;
import com.starry.common.constant.UserConstants;
import com.starry.common.utils.StringUtils;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

/**
 * @author admin
 */
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UserDetailsService userDetailsService;
    @Resource
    private JwtToken jwtTokenUtil;
    @Resource
    private SysMenuService menuService;
    @Resource
    private SysRoleService roleService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private ISysTenantService SysTenantService;

    @Override
    public String login(String username, String password) {
        String token = null;
        try {
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                throw new BadCredentialsException("密码不正确");
            }
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,
                    null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            // 登录成功记录日志
            AsyncManager.me().execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_SUCCESS, "登录成功"));
            JwtUser jwtUser = (JwtUser) authentication.getPrincipal();
            token = jwtTokenUtil.createToken(jwtUser);
        } catch (AuthenticationException e) {
            log.warn("登录异常:{}", e.getMessage());
            // 登录失败记录日志
            AsyncManager.me().execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_FAIL, e.getMessage()));
        }
        return token;
    }

    @Override
    public Set<String> getMenuPermission(SysUserEntity user) {
        Set<String> perms = new HashSet<>();
        // 超级管理员拥有所有权限
        if (SecurityUtils.isAdmin(user)) {
            perms.add("*:*:*");
        } else {
            perms = menuService.selectMenuPermsByUserId(user.getUserId());
        }
        return perms;
    }

    @Override
    public Set<String> getRolePermission(SysUserEntity user) {
        Set<String> roles = new HashSet<>();
        // 超级管理员拥有所有权限
        if (SecurityUtils.isAdmin(user)) {
            roles.add("admin");
        } else {
            roles = roleService.selectRolePermissionByUserId(user.getUserId());
        }
        return roles;
    }

    @Override
    public LoginUser tenantLogin(String tenantId, String username, String password) {
        // LoginUser userInfo = this.getLoginUserInfo(username);
        return null;
    }

    @Override
    public LoginUser newLogin(String username, String password, String tenantKey) {
        // 用户名或密码为空 错误
        if (StringUtils.isAnyBlank(username, password, tenantKey)) {
            // 登录记录日志
            AsyncManager.me().execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_FAIL, "用户名/密码必须填写"));
            throw new ServiceException("用户/密码必须填写");
        }
        // 密码如果不在指定范围内 错误
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
            // 登录记录日志
            AsyncManager.me().execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_FAIL, "用户密码不在指定范围"));
            throw new ServiceException("用户密码不在指定范围");
        }
        // 用户名不在指定范围内 错误
        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
                || username.length() > UserConstants.USERNAME_MAX_LENGTH) {
            // 登录记录日志
            AsyncManager.me().execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_FAIL, "用户名不在指定范围"));
            throw new ServiceException("用户名不在指定范围");
        }
        SysTenantEntity tenant = SysTenantService.selectByTenantKey(tenantKey);
        LoginUser userInfo = this.getLoginUserInfo(username, tenant.getTenantId());
        if (userInfo == null) {
            // 登录记录日志
            AsyncManager.me().execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_FAIL, "用户名不存在"));
            throw new ServiceException("用户名不存在");
        }
        SysUserEntity user = userInfo.getUser();
        if (!SecurityUtils.matchesPassword(password, user.getPassWord())) {
            // 登录记录日志
            AsyncManager.me().execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_FAIL, "密码错误"));
            throw new ServiceException("密码错误");
        }
        // 线程塞入租户ID
        SecurityUtils.setTenantId(Convert.toStr(user.getTenantId()));
        if (user.getStatus() == 1) {
            // 登录记录日志
            AsyncManager.me().execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_FAIL, "用户已停用，请联系管理员"));
            throw new ServiceException("对不起，您的账号：" + username + " 已停用，请联系管理员");
        }
        // 先查询是否被停用了租户
        if (userInfo.getTenantStatus() != null && userInfo.getTenantStatus() == 1) {
            // 登录记录日志
            AsyncManager.me().execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_FAIL, "当前租户已经被停用，请联系管理员"));
            throw new ServiceException("当前租户已经被停用，请联系管理员");
        }
        if (userInfo.getTenantEndDate() != null && userInfo.getTenantEndDate().compareTo(new Date()) < 0) {
            // 登录记录日志
            AsyncManager.me()
                    .execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_FAIL, "当前租户已超过租赁日期，请联系管理员"));
            throw new ServiceException("当前租户已超过租赁日期，请联系管理员");
        }
        AsyncManager.me().execute(AsyncFactory.recordLoginLog(username, Constants.LOGIN_SUCCESS, "登录成功"));
        return userInfo;
    }

    @Override
    public LoginUser getLoginUserInfo(String userName, String tenantId) {
        SysUserEntity sysUser;
        if (userName.equals("sysadmin")) {
            sysUser = sysUserService.selectUserByUserNameAndTenantId(userName, tenantId);
        } else {
            sysUser = sysUserService.selectUserByUserNameAndTenantId(userName, tenantId);
        }

        if (StringUtils.isNotNull(sysUser)) {
            // SecurityUtils.setTenantId(sysUser.getTenantId());
            // 角色集合
            Set<String> roles = this.getRolePermission(sysUser);
            // 权限集合
            Set<String> permissions = this.getMenuPermission(sysUser);
            // 查询租户信息
            SysTenantEntity tenant = SysTenantService.selectSysTenantByTenantId(sysUser.getTenantId());
            LoginUser sysUserVo = new LoginUser();
            sysUserVo.setUser(sysUser);
            sysUserVo.setRoles(roles);
            sysUserVo.setPermissions(permissions);
            if (tenant != null) {
                sysUserVo.setTenantEndDate(tenant.getTenantTime());
                sysUserVo.setTenantStatus(Integer.valueOf(tenant.getTenantStatus()));
            }
            return sysUserVo;
        }
        return null;
    }

    @Override
    public LoginUser getLoginUserInfo(String userId) {
        SysUserEntity sysUser = sysUserService.selectUserById(userId);
        Set<String> roles = this.getRolePermission(sysUser);
        // 权限集合
        Set<String> permissions = this.getMenuPermission(sysUser);
        // 查询租户信息
        SysTenantEntity tenant = SysTenantService.selectSysTenantByTenantId(sysUser.getTenantId());
        LoginUser sysUserVo = new LoginUser();
        sysUserVo.setUser(sysUser);
        sysUserVo.setRoles(roles);
        sysUserVo.setPermissions(permissions);
        if (tenant != null) {
            sysUserVo.setTenantEndDate(tenant.getTenantTime());
            sysUserVo.setTenantStatus(Integer.valueOf(tenant.getTenantStatus()));
        }
        return sysUserVo;
    }
}
