package cn.com.countrygarden.bi.main.service.phoenix.impl;

import cn.com.countrygarden.bi.main.exception.ServiceException;
import cn.com.countrygarden.bi.main.model.phoenix.PhoenixSalesBody;
import cn.com.countrygarden.bi.main.model.phoenix.PhoenixSalesResponse;
import cn.com.countrygarden.bi.main.service.phoenix.PhoenixSalesHttpClientService;
import com.alibaba.fastjson.JSON;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.Key;
import java.util.Base64;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

@Service
public class PhoenixSalesHttpClientServiceImpl implements PhoenixSalesHttpClientService {

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

    @Autowired
    @Qualifier("applicationProperties")
    private Properties applicationProperties;

    MediaType JSONType = MediaType.parse("application/json; charset=utf-8");

    OkHttpClient client = new OkHttpClient().newBuilder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build();

    String PHOENIX_SALES_HOST;
    String PHOENIX_SALES_COMPANY_ID;
    String PHOENIX_SALES_CHANNEL_ID;
    String PHOENIX_SALES_KEY;
    String PHOENIX_SALES_IV;

    /**
     * CBC加密
     *
     * @param key   密钥
     * @param keyiv IV
     * @param data  明文
     * @return Base64编码的密文
     * @throws Exception
     */
    @Override
    public byte[] des3EncodeCBC(byte[] key, byte[] keyiv, byte[] data)
            throws Exception {
        Key deskey;
        DESedeKeySpec spec = new DESedeKeySpec(key);
        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
        deskey = keyfactory.generateSecret(spec);
        Cipher cipher = Cipher.getInstance("desede" + "/CBC/PKCS5Padding");
        IvParameterSpec ips = new IvParameterSpec(keyiv);
        cipher.init(Cipher.ENCRYPT_MODE, deskey, ips);
        byte[] bOut = cipher.doFinal(data);
        return bOut;
    }

    /**
     * CBC解密
     *
     * @param key   密钥
     * @param keyiv IV
     * @param data  Base64编码的密文
     * @return 明文
     * @throws Exception
     */
    @Override
    public byte[] des3DecodeCBC(byte[] key, byte[] keyiv, byte[] data)
            throws Exception {
        Key deskey;
        DESedeKeySpec spec = new DESedeKeySpec(key);
        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("desede");
        deskey = keyfactory.generateSecret(spec);
        Cipher cipher = Cipher.getInstance("desede" + "/CBC/PKCS5Padding");
        IvParameterSpec ips = new IvParameterSpec(keyiv);
        cipher.init(Cipher.DECRYPT_MODE, deskey, ips);
        byte[] bOut = cipher.doFinal(data);
        return bOut;
    }

    @Override
    public String encodeToString(String string) throws Exception {
        byte[] encodeByte = des3EncodeCBC(PHOENIX_SALES_KEY.getBytes(), PHOENIX_SALES_IV.getBytes(), string.getBytes());
        return Base64.getEncoder().encodeToString(encodeByte);
    }

    @Override
    public String decodeString(String string) throws Exception {
        byte[] byteToDecode = Base64.getDecoder().decode(string.getBytes());
        byte[] decodeByte = des3DecodeCBC(PHOENIX_SALES_KEY.getBytes(), PHOENIX_SALES_IV.getBytes(), byteToDecode);
        return new String(decodeByte);
    }

    @Override
    public String post(String api, Map<String, Object> params) {
        initConfig();

        String responsePackage;

        String url = getUrl(api);

        String packageData;
        long time = System.currentTimeMillis();
        String timeStr = time + "";

        try {
            String paramsJSON = JSON.toJSONString(params);
            packageData = encodeToString(paramsJSON);
            timeStr = encodeToString(timeStr);
        } catch (Exception e) {
            logger.error("[凤凰会]请求参数加密失败: " + e.getMessage(), e);
            throw new ServiceException("[凤凰会]请求参数加密失败");
        }


        PhoenixSalesBody phoenixSalesBody = new PhoenixSalesBody();
        phoenixSalesBody.setCompanyid(PHOENIX_SALES_COMPANY_ID);
        phoenixSalesBody.setChannelid(PHOENIX_SALES_CHANNEL_ID);
        phoenixSalesBody.setPackageData(packageData);
        phoenixSalesBody.setTime(timeStr);
        String json = JSON.toJSONString(phoenixSalesBody);

        RequestBody body = RequestBody.create(JSONType, json.toString());
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();

        Response response;
        String responseString;
        try {
            response = client.newCall(request).execute();
            responseString = response.body().string();
        } catch (Exception e) {
            logger.error("[凤凰会]请求失败: " + e.getMessage(), e);
            throw new ServiceException("[凤凰会]请求失败");
        }

        PhoenixSalesResponse salesResponse = JSON.parseObject(responseString, PhoenixSalesResponse.class);
        try {
            responsePackage = decodeString(salesResponse.getPackageData());
        } catch (Exception e) {
            logger.error("[凤凰会]返回解密失败: " + e.getMessage(), e);
            throw new ServiceException("[凤凰会]返回解密失败");
        }

        return responsePackage;
    }


    private String getUrl(String api) {
        return String.format("%s/%s", PHOENIX_SALES_HOST, StringUtils.trimTrailingCharacter(api, '\\'));
    }

    private void initConfig() {
        PHOENIX_SALES_HOST = applicationProperties.getProperty("phoenix.sales.host", "");
        PHOENIX_SALES_COMPANY_ID = applicationProperties.getProperty("phoenix.sales.companyid", "");
        PHOENIX_SALES_CHANNEL_ID = applicationProperties.getProperty("phoenix.sales.channelid", "");
        PHOENIX_SALES_KEY = applicationProperties.getProperty("phoenix.sales.key", "");
        PHOENIX_SALES_IV = applicationProperties.getProperty("phoenix.sales.iv", "");
    }
}
