/*
 * Copyright (c) 2023 codvision.com All Rights Reserved.
 */

package com.codvision.webapi.remote.decoder;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.codvision.commoncore.common.ResponseEntity;
import com.codvision.commoncore.exception.BusinessException;
import com.codvision.webapi.config.EncryptProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.FeignException;
import feign.Response;
import feign.Util;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;

import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

/**
 * 解密配置
 *
 * @author lingee
 * @date 2023/8/2
 */
@Slf4j
public class BaseResponseDecoder implements Decoder {

    @Override
    public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
        Response.Body body = response.body();
        if (response.status() == HttpStatus.NOT_FOUND.value() || response.status() == HttpStatus.NO_CONTENT.value()) {
            return Util.emptyValueOf(type);
        }
        if (body == null) {
            return null;
        }
        if (byte[].class.equals(type)) {
            return Util.toByteArray(body.asInputStream());
        }
        if (StrUtil.contains(type.getTypeName(), "com.codvision.commoncore.common.ResponseEntity")) {
            String bodyString = Util.toString(body.asReader(Util.UTF_8));
            // 解密
            return decryptResponse(bodyString, type);
        }
        throw new DecodeException(response.status(),
                String.format("%s is not a type supported by this decoder.", type), response.request());
    }

    private Object decryptResponse(String bodyString, Type type) throws IOException {
        EncryptProperties encryptProperties = SpringUtil.getBean(EncryptProperties.class);
        ObjectMapper objectMapper = SpringUtil.getBean(ObjectMapper.class);

        ResponseEntity<String> responseEntity = JSONUtil.toBean(bodyString, ResponseEntity.class);

        AES aes = new AES(Mode.CBC, Padding.ZeroPadding, new SecretKeySpec(encryptProperties.getSecretKey().getBytes(), "AES"),
                new IvParameterSpec(encryptProperties.getSecretKey().getBytes()));

        byte[] decryptedBody;
        try {
            decryptedBody = aes.decrypt(StrUtil.str(responseEntity.getData(), Charset.defaultCharset()));
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new BusinessException(30001, "请检查encryption参数值是否已加密传输");
        }

        return objectMapper.readValue(decryptedBody, type.getClass());
    }
}
