package com.hdkj.lt.core.plugins.hussar;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.google.common.collect.Lists;
import com.hdkj.lt.base.constants.SystemGlobalConstant;
import com.hdkj.lt.base.exception.ExceptionCast;
import com.jxdinfo.hussar.common.security.SecurityUtils;
import com.jxdinfo.hussar.common.security.SecurityUser;
import com.jxdinfo.hussar.encrypt.util.SM2Util;
import com.hdkj.hussar.ApiResponse;
import com.hdkj.hussar.ResultCode;
import com.jxdinfo.hussar.support.cache.util.HussarCacheUtil;
import com.jxdinfo.hussar.support.security.plugin.oauth2.logic.SecurityOAuth2Constants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author wucx
 * @Date 2023/3/20 17:15
 * @Version 1.0
 */
@Slf4j
//@Component
@RequiredArgsConstructor
public class HussarTokenUtils {

    // nacos配置信息
    @Value("${spring.cloud.nacos.discovery.server-addr:}")
    private String serverAddr;
    @Value("${spring.cloud.nacos.discovery.namespace:}")
    private String namespace;
    @Value("${spring.cloud.nacos.discovery.username:}")
    private String username;
    @Value("${spring.cloud.nacos.discovery.password:}")
    private String password;
    @Value("${spring.cloud.nacos.discovery.access-key:}")
    private String accessKey;
    @Value("${spring.cloud.nacos.discovery.secret-key:}")
    private String secretKey;

    // 获取token信息
    @Value("${lt.junit.userName}")
    private String userAccount;
    @Value("${lt.junit.password}")
    private String userPwd;

    private String gatewayUri;

    private final RestTemplate connPoolRestTemplate;

    @PostConstruct
    public void initGatewayUri() {
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
        properties.put(PropertyKeyConst.NAMESPACE, namespace);
        properties.put(PropertyKeyConst.USERNAME, username);
        properties.put(PropertyKeyConst.PASSWORD, password);
        properties.put(PropertyKeyConst.ACCESS_KEY, accessKey);
        properties.put(PropertyKeyConst.SECRET_KEY, secretKey);
        try {
            NamingService namingService = NamingFactory.createNamingService(properties);
            Instance instance = namingService.selectOneHealthyInstance(SystemGlobalConstant.SERVICE_NAME_GATEWAY);
            Assert.notNull(instance, "description failed to abtain the gateway server address, gateway server does not exist");
            gatewayUri = getUriByInstance(instance);
            // 获取加密公钥
            ApiResponse<?> respEntity = connPoolRestTemplate.getForObject(gatewayUri.concat("/hussarWeb/vue/baseData/getBaseData"), ApiResponse.class);
            if (ResultCode.SUCCESS.getCode() != Objects.requireNonNull(respEntity).getCode()) {
                ExceptionCast.cast("加密公钥接口数据获取失败！");
            }
            JSONObject result = JSONObject.parseObject(JSON.toJSONString(Objects.requireNonNull(respEntity).getData()));
            if (StringUtils.isBlank(Objects.requireNonNull(result).getString("hussarEK"))) {
                ExceptionCast.cast("未获取到加密公钥信息！");
            }
            if (result.getBoolean("enablePwEncryption")) { //默认不开启加密，直接赋值用户密码，开启加密时，获取密码的加密内容
                userPwd = SM2Util.encrypt(userPwd, result.getString("hussarEK"));
            }
        } catch (NacosException e) {
            log.error("description failed to abtain the gateway server address: {}", e.getMessage());
        }
    }

    private String getUriByInstance(Instance instance) {
        return "http://".concat(instance.getIp()).concat(":").concat(String.valueOf(instance.getPort()));
    }

    public HttpHeaders initHeaders() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String authorization = Objects.isNull(securityUser) ? this.getToken() : securityUser.getAccessToken();
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.AUTHORIZATION, authorization);
        return headers;
    }

    public String getToken() {
        List<String> list = HussarCacheUtil.getKeysRightLike("hussar-token", "hussar-token:oauth2:access-token:");
        String token = list.stream().filter(e -> StringUtils.equals(e, list.get(list.size() - 1))).map(e -> e.substring(e.lastIndexOf(":") + 1)).collect(Collectors.joining());
        if (StringUtils.isEmpty(token)) {
            // 获取HussarToken数据
            String authUri = String.format("%s/auth/oauth2/token?loginType=default&grant_type=password&username=%s&password=%s", gatewayUri, userAccount, userPwd);
            // 接口header信息
            HttpHeaders headers = new HttpHeaders();
            headers.set(SecurityOAuth2Constants.Param.client_id, "hussar-base");
            headers.setAccept(Lists.newArrayList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
            HttpEntity<MultiValueMap<String, Object>> formEntity = new HttpEntity<>(headers);
            ResponseEntity<ApiResponse> respEntity = connPoolRestTemplate.exchange(authUri, HttpMethod.GET, formEntity, ApiResponse.class);
            if (ResultCode.SUCCESS.getCode() != Objects.requireNonNull(respEntity.getBody()).getCode()) {
                ExceptionCast.cast("HussarToken接口数据获取失败！");
            }
            JSONObject result = JSONObject.parseObject(JSON.toJSONString(Objects.requireNonNull(respEntity.getBody()).getData()));
            if (StringUtils.isBlank(Objects.requireNonNull(result).getString(SecurityOAuth2Constants.Param.access_token))) {
                ExceptionCast.cast("未获取到指定HussarToken信息！");
            }
            token = result.getString(SecurityOAuth2Constants.Param.access_token);
        }
        return token;
    }

}
