package cn.sh.stc.sict.cloud.common.security.service;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.util.AuthUtils;
import cn.sh.stc.sict.cloud.upms.dto.UserInfo;
import cn.sh.stc.sict.cloud.upms.feign.RemoteUserService;
import cn.sh.stc.sict.cloud.upms.model.SysUserBase;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @Description 用户详细信息
 * @Author
 * @Date
 */
@Slf4j
@Service
@AllArgsConstructor
public class SictUserDetailsServiceImpl implements SictUserDetailsService {

    private static final String BASIC_ = "Basic ";
    private final RemoteUserService remoteUserService;
    private final CacheManager cacheManager;

    /**
     * 用户密码登录
     *
     * @param username 用户名
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    @SneakyThrows
    public UserDetails loadUserByUsername(String username) {
        String key = username;
        Cache cache = cacheManager.getCache(RedisCacheConstant.USER_DETAILS);
        if (!StrUtil.containsAny(key, StringPool.COLON)) {
            key = key + StringPool.COLON + getAppId();
        }
        if (cache != null && cache.get(key) != null) {
            SictUser user = (SictUser) cache.get(key).get();
            return user;
        }
        String appId = getAppId();
        R<UserInfo> result = remoteUserService.info(appId, username, SecurityConstants.FROM_IN);
        UserDetails userDetails = getUserDetails(result);
        cache.put(key, userDetails);
        return userDetails;
    }


    /**
     * 根据社交登录code 登录
     *
     * @param inStr TYPE@CODE
     * @return UserDetails
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserBySocial(String inStr) throws UsernameNotFoundException {
        Cache cache = cacheManager.getCache(RedisCacheConstant.USER_DETAILS);
        String appId = getAppId();
        log.error("login =============>> type = social, appId = {}, inStr = {}", appId, inStr);
        R<UserInfo> result = remoteUserService.social(appId, inStr, SecurityConstants.FROM_IN);
        UserDetails userDetails = getUserDetails(result);
        cache.put(userDetails.getUsername(), userDetails);
        return userDetails;
    }

    /**
     * 构建userdetails
     *
     * @param result 用户信息
     * @return
     */
    private UserDetails getUserDetails(R<UserInfo> result) {
        if (result == null || result.getData() == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        UserInfo info = result.getData();
        if (StrUtil.isBlank(info.getAppId())) {
            info.setAppId(getAppId());
        }
        Set<String> dbAuthsSet = new HashSet<>();
        if (ArrayUtil.isNotEmpty(info.getRoles())) {
            // 获取角色
            Arrays.stream(info.getRoles()).forEach(roleId -> dbAuthsSet.add(SecurityConstants.ROLE + roleId));
            // 获取资源
            dbAuthsSet.addAll(Arrays.asList(info.getPermissions()));
        }
        Collection<? extends GrantedAuthority> authorities
                = AuthorityUtils.createAuthorityList(dbAuthsSet.toArray(new String[0]));
        SysUserBase user = info.getSysUserBase();
        boolean enabled = Constant.BYTE_NO.equals(user.getStatus());
        // 构造security用户
        if (StrUtil.isBlank(user.getUserName())) {
            user.setUserName(user.getId().toString());
        }

        String userName = user.getUserName() + StringPool.COLON + info.getAppId();
        return new SictUser(user.getId(), user.getPhone(), info.getOpenId(), info.getAppId(), userName, SecurityConstants.BCRYPT + user.getPasswd(), enabled,
                true, true, !Constant.BYTE_YES.equals(user.getStatus()), authorities);
    }

    private static String getAppId() {
        String appId = "";
        try {
            HttpServletRequest request = ((ServletRequestAttributes) Objects
                    .requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            if (SecurityConstants.OAUTH_TOKEN_URL.equals(request.getRequestURI()) || (new AntPathRequestMatcher(SecurityConstants.MOBILE_TOKEN_URL)).matches(request)) {
                String header = request.getHeader(HttpHeaders.AUTHORIZATION);
                if (header == null || !header.startsWith(BASIC_)) {
                    log.error("登录异常：请求头中client信息为空!");
                } else {
                    String[] tokens = AuthUtils.extractAndDecodeHeader(header);
                    assert tokens.length == 2;
                    appId = tokens[0];
                }
            }
        } catch (Exception ex) {

        }
        return appId;
    }
}
