package com.bcxin.ins.service.oauth;

import com.alibaba.fastjson.JSON;
import com.bcxin.ins.dto.Result;
import com.bcxin.ins.dto.oauth.AccessToken;
import com.bcxin.ins.dto.oauth.OAuthTokenxRequest;
import com.bcxin.ins.service.user.ClientUserService;
import com.bcxin.ins.spring.util.JedisUtils;
import com.bcxin.ins.util.AESUtil;
import com.bcxin.ins.util.MathUtil;
import com.bcxin.ins.vo.ClientUserVo;
import com.bcxin.ins.vo.ConstProp;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.apache.oltu.oauth2.as.issuer.MD5Generator;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.error.OAuthError;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * OAuthToken2.0 客户端授权
 *
 * @author zhangye
 * @version 1.0
 */
@Service
@Transactional
public class OAuthServiceImpl implements OAuthService {

    private static Logger logger = LoggerFactory.getLogger(OAuthServiceImpl.class);

    @Autowired
    private ClientUserService userService;

    /**
     * 获取客户端授权AccessToken
     */
    @Override
    public Result saveDispatch(HttpServletRequest request, HttpServletResponse response, String clientType)
            throws Exception {

        OAuthTokenxRequest oauthRequest = new OAuthTokenxRequest(request);
        Map<Boolean, OAuthResponse> handleResult = handle(oauthRequest,clientType);

        if (handleResult.containsKey(true)) {
            return Result.success(Result.SUCCESS_MSG,
                    handleResult.get(true) == null ? null : JSON.parse(handleResult.get(true).getBody()));
        } else {
            return Result.fail(handleResult.get(false) == null ? "参数错误！" : JSON.parseObject(handleResult.get(false).getBody()).getString("error_description"));
        }
    }

    /**
     * 校验客户端参数，验证成功返回AccessToken
     *
     * @return
     * @throws OAuthProblemException
     * @throws OAuthSystemException
     */
    private Map<Boolean, OAuthResponse> handle(OAuthTokenxRequest oauthRequest, String clientType) throws OAuthProblemException, OAuthSystemException {

        Map<Boolean, OAuthResponse> result = new HashMap<Boolean, OAuthResponse>();
        OAuthResponse validateResponse = null;


        String userName = oauthRequest.getUsername();
        String passWord = oauthRequest.getPassword();
        String publicKey = oauthRequest.getPublicKey();

        if(StringUtils.isEmpty(userName) || StringUtils.isEmpty(passWord) || StringUtils.isEmpty(publicKey)){
            validateResponse = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_GRANT).setErrorDescription("参数错误").buildJSONMessage();

            result.put(false, validateResponse);
            return result;
        }

        try {
            byte[] bytes = publicKey.getBytes();
            byte[] data = Hex.decodeHex(passWord.toCharArray());
            byte[] s = new byte[0];
            s = AESUtil.AES_CBC_Decrypt(data, bytes, bytes);
            passWord = new String(s);
            if(!userName.equals(passWord)){
                validateResponse = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                        .setError(OAuthError.TokenResponse.INVALID_GRANT).setErrorDescription("用户或者密码错误").buildJSONMessage();
                result.put(false, validateResponse);
                return result;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        ClientUserVo userVo = userService.getClientUserVo(userName, MathUtil.getType(userName));
        if(userVo == null){
            validateResponse = OAuthResponse.errorResponse(HttpServletResponse.SC_BAD_REQUEST)
                    .setError(OAuthError.TokenResponse.INVALID_GRANT).setErrorDescription("用户不存在").buildJSONMessage();

            result.put(false, validateResponse);
            return result;
        }

        OAuthResponse oAuthResponse = handleAfterValidation(oauthRequest.getRedirectURI(),clientType, userVo);
        result.put(true, oAuthResponse);
        return result;
    }

    private OAuthResponse handleAfterValidation(String redirectURI, String clientType,ClientUserVo userVo) throws OAuthProblemException, OAuthSystemException {
        AccessToken accessToken = retrieveAccessToken(clientType,userVo);
        OAuthResponse tokenResponse = createTokenResponse(redirectURI,accessToken);
        return tokenResponse;

    }

    private OAuthResponse createTokenResponse(String redirectURI,AccessToken accessToken)
            throws OAuthSystemException {
        final OAuthASResponse.OAuthTokenResponseBuilder builder = OAuthASResponse
                .tokenResponse(HttpServletResponse.SC_OK).location(redirectURI)
                .setAccessToken(accessToken.getTokenId())
                .setExpiresIn(String.valueOf(accessToken.currentTokenExpiredSeconds()))
                .setTokenType(accessToken.getTokenType());
        final String refreshToken = accessToken.getRefreshToken();
        if (StringUtils.isNotEmpty(refreshToken)) {
            builder.setRefreshToken(refreshToken);
        }
        if (StringUtils.isNotEmpty(redirectURI)) {
            builder.setParam("redirect_uri", redirectURI);
        }
        return builder.buildJSONMessage();
    }

    @Override
    public AccessToken getAccessToken(String clientType, ClientUserVo userVo, String tokenId) throws OAuthSystemException {
        String loginId = userVo.getOid();
        AccessToken accessToken = null;
        // 用客户端id和用户账号获取accessToken
        String value = JedisUtils.get(ConstProp.REDIS_HEAD_UID+loginId);
        // 获取accessToken
        if (StringUtils.isNotEmpty(value)) {
            accessToken = (AccessToken) JedisUtils.getObject(ConstProp.REDIS_HEAD_BLB_TOKEN+value);
            // 只允许一个账号登陆
            if (accessToken != null) {
                return accessToken;
            }
        }
        accessToken = createAccessToken(userVo,clientType,tokenId);
        return accessToken;
    }

    /**
     * 验证AccessToken是否已经存在，不存在则新创建
     */
    private AccessToken retrieveAccessToken(String clientType, ClientUserVo userVo) throws OAuthSystemException {
        String loginId = userVo.getOid();
        AccessToken accessToken = null;
        // 用客户端id和用户账号获取accessToken
        String value = JedisUtils.get(ConstProp.REDIS_HEAD_UID+loginId);
        // 获取accessToken
        if (StringUtils.isNotEmpty(value)) {
            accessToken = (AccessToken) JedisUtils.getObject(ConstProp.REDIS_HEAD_BLB_TOKEN+value);
            // 只允许一个账号登陆
            if (accessToken != null) {
                JedisUtils.del(loginId);
                JedisUtils.delObject(ConstProp.REDIS_HEAD_BLB_TOKEN+accessToken.getTokenId());
            }
        }
        accessToken = createAccessToken(userVo,clientType,"");
        return accessToken;
    }

    /**
     * 创建AccessToken
     *
     * @param userVo
     * @param clientType
     * @return
     * @throws OAuthSystemException
     */
    private AccessToken createAccessToken(ClientUserVo userVo,String clientType,String tokenId) throws OAuthSystemException {
        // access_token生成器
        OAuthIssuer oauthIssuer = new OAuthIssuerImpl(new MD5Generator());
        // access_token
        String accessTokenString = oauthIssuer.accessToken();
        if(StringUtils.isNotEmpty(tokenId)){
            accessTokenString = tokenId;
        }
        AccessToken accessToken = null;
        int seconds = 0; // 过期时间
        // IM 客户端KEY
        seconds = AccessToken.ACCESS_TOKEN_WEB_VALIDITY_SECONDS;
        // 根据用户ID获取公司ID
        accessToken = new AccessToken();
        accessToken.setWebId(userVo.getWeb_id());
        accessToken.setWebType(userVo.getWeb_type());
        accessToken.setUserId(userVo.getOid());
        accessToken.setName(userVo.getReal_name());
        accessToken.setLoginName(userVo.getLogin_name());
        accessToken.setTokenId(accessTokenString);
        accessToken.setTokenExpiredSeconds(seconds);
        accessToken.setRefreshToken(oauthIssuer.refreshToken());
        accessToken.setUserVo(userVo);
        // 客户端id和用户名作为key access_token作为value存入redis
        JedisUtils.set(ConstProp.REDIS_HEAD_UID+userVo.getOid(), accessTokenString, seconds);
        JedisUtils.setObject(ConstProp.REDIS_HEAD_BLB_TOKEN+accessTokenString, accessToken, seconds);
        return accessToken;
    }

    /**
     * 获取AccessToken信息
     */
    @Override
    public AccessToken getAccessToken(String access_token) {
        AccessToken accessToken = (AccessToken)JedisUtils.getObject(ConstProp.REDIS_HEAD_BLB_TOKEN+access_token);
        if (accessToken != null) {
            // accessToken过期
            if (accessToken.tokenExpired()) {
                accessToken = null;
            }
        }
        return accessToken;
    }

    public static void main(String[] args) throws Exception {
        String userName = "15601000000";
        String passWord = "86b955d41be7a1ce4b8db67da688103e";
        String publicKey = "wdMFAbNpSmRJEmOl";
        if (StringUtils.isNotEmpty(publicKey)) {
            byte[] bytes = publicKey.getBytes();

            byte[] data = Hex.decodeHex(passWord.toCharArray());
            byte[] s = AESUtil.AES_CBC_Decrypt(data, bytes, bytes);
            passWord = new String(s);
            System.out.println(passWord);
        } else {
        }
    }

}
