package com.infoepoch.pms.dispatchassistant.common.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.infoepoch.pms.commons.utils.ResponseUtils;
import com.infoepoch.pms.dispatchassistant.common.constant.StoreKeys;
import com.infoepoch.pms.dispatchassistant.common.exception.ValidationException;
import com.infoepoch.pms.dispatchassistant.domain.basic.store.KeyValueStoreService;
import com.infoepoch.pms.dispatchassistant.domain.basic.user.IUserRepository;
import com.infoepoch.pms.dispatchassistant.domain.basic.user.User;
import com.infoepoch.pms.dispatchassistant.domain.oa.SSOResponse;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author guoshun
 * @description:
 * @date 2022/4/1316:45
 */
@Component
public class DecodeJWTToken {

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

    private static volatile Map<String, JWTVerifier> verifierMap = new HashMap();

    private String signSecret = "infoepoch";

    @Autowired
    private RestTemplateUtils restTemplateUtils;
    @Autowired
    private KeyValueStoreService keyValueStoreService;
    @Autowired
    private IUserRepository userRepository;



    public String getUserName(HttpServletRequest request) {
        String userName = getUserIdByDecodeToken(request);
        return userName;
    }

    public String getUserIdByDecodeToken(HttpServletRequest request) {

        String userName = null;
        Cookie[] cookies = request.getCookies();
        logger.info("cookie = " +cookies );
        if (cookies != null && cookies.length != 0) {

            Cookie pmsWebCookie = Arrays.stream(cookies).filter((cookie) -> {
                return ResponseUtils.isCkName(cookie,"pms-web");
            }).findAny().orElse(null);
            Cookie ObSSOCookie = Arrays.stream(cookies).filter((cookie) -> {
                return ResponseUtils.isCkName(cookie,"ObSSOCookie");
            }).findAny().orElse(null);
            if (pmsWebCookie != null) {
                String token = pmsWebCookie.getValue();
                logger.info(" pms-web cookie " + token);
                DecodedJWT decodedJWT = verifySessionToken(token, signSecret);
                userName = decodedJWT.getClaim("accountName").asString();
            } else if (ObSSOCookie != null) {
                String token = ObSSOCookie.getValue();
                logger.info(" ObSSOCookie cookie " + token);
                User user = getUserByToken(token);
               // JsonNode result = restTemplateUtils.postForLinkedMultiValueMap(keyValueStoreService.queryValueByKey(StoreKeys.PMS_API_URL), param);
                userName = user.getUsername();
            }
            return userName;
        } else {
            return null;
        }
    }
    /**
     * 根据token获取用户信息
     *
     * @param token
     * @return
     */
    private User getUserByToken(String token) {
        try {
            URL httpUrl = new URL(keyValueStoreService.queryValueByKey(StoreKeys.OA_LOGIN_PAGE_URL));
            logger.info("ssoLogin createSsoSession url: " + httpUrl.toString());
            HttpHeaders requestHeader = new HttpHeaders();
            requestHeader.setContentType(MediaType.APPLICATION_XML);
            StringBuffer xmlString = new StringBuffer();
            xmlString.append("<request><token>")
                    .append(token)
                    .append("</token></request>");
            // 创建 HttpEntity
            String url = httpUrl.toString();
            HttpEntity<String> requestEntity = new HttpEntity<>(xmlString.toString(), requestHeader);
            String responseEntity = invokeUrl(url, requestEntity);
            logger.info("responseEntity: " + responseEntity);
            //构造输入流
            InputStream is = IOUtils.toInputStream(responseEntity);
            SSOResponse response = (SSOResponse) XMLProxy.getInstance().fromResponseXML(is);// 从SSO获取响应结果
            String status = response.getStatus();
            logger.info("SSOResponse 信息：" + JsonUtils.objectToJson(response));
            if ("ok".equals(status)) {
                String username = response.getUid();
                User user = userRepository.selectByUsername(StringTool.getString(username, "").toLowerCase());
                if (user == null) {
                    logger.info("用户信息为空。location:TodoService.getUserByToken");
                }
                return user;
            } else {
                logger.info("OA获取用户信息失败: " + response.getMessage());
                throw new ValidationException("OA获取用户信息失败");
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
            logger.info("生成OA登录地址URL报错: " + e.getMessage());
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            logger.info("获取用户信息失败: " + e.getMessage());
            return null;
        }
    }


    /*
     *
     * 功能描述: 注册集成RestTemplate
     * @Param: [url, requestEntity]
     * @Return: org.springframework.http.ResponseEntity<java.lang.String>
     * @Author: jill
     * @Date: 2020/3/31 18:27
     */
    private String invokeUrl(String url, HttpEntity<String> requestEntity) {
        StringHttpMessageConverter m = new StringHttpMessageConverter(Charset.forName("UTF-8"));
        RestTemplate restTemplate = new RestTemplateBuilder().additionalMessageConverters(m).build();
        return restTemplate.postForObject(url, requestEntity, String.class);

    }


    public static DecodedJWT verifySessionToken(String tokenString, String signingToken) {
        return verifyToken(tokenString, signingToken);
    }

    static DecodedJWT verifyToken(String tokenString, String signingToken) {
        JWTVerifier verifier = (JWTVerifier) verifierMap.get(signingToken);
        if (verifier == null) {
            synchronized (verifierMap) {
                verifier = (JWTVerifier) verifierMap.get(signingToken);
                if (verifier == null) {
                    Algorithm algorithm = Algorithm.HMAC512(signingToken);
                    verifier = JWT.require(algorithm).build();
                    verifierMap.put(signingToken, verifier);
                }
            }
        }

        DecodedJWT jwt = verifier.verify(tokenString);
        return jwt;
    }

}

class OALoginInfoDto {

    // 用户id
    private String userId;

    //员工编号
    private String employeeNumber;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getEmployeeNumber() {
        return employeeNumber;
    }

    public void setEmployeeNumber(String employeeNumber) {
        this.employeeNumber = employeeNumber;
    }

    @Override
    public String toString() {
        return "OALoginInfoDto{" +
                "userId='" + userId + '\'' +
                ", employeeNumber='" + employeeNumber + '\'' +
                '}';
    }
}
