package com.qingyun.framework.encrypt.advice;


import cn.hutool.crypto.SecureUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qingyun.framework.encrypt.annotation.Encrypt;
import com.qingyun.framework.encrypt.config.SecretKeyConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;


@Slf4j
@ControllerAdvice
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> {

	private boolean encrypt;

	@Autowired
	private ObjectMapper mapper;

	@Autowired
	private SecretKeyConfig secretKeyConfig;

	private static ThreadLocal<Boolean> encryptLocal = new ThreadLocal<>();

	@Override
	public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
		encrypt = false;
		if (returnType.getMethod().isAnnotationPresent(Encrypt.class) && secretKeyConfig.isOpen()) {
			encrypt = true;
		} else if (returnType.getDeclaringClass().isAnnotationPresent(Encrypt.class) && secretKeyConfig.isOpen()) {
			encrypt = true;
		}
		return encrypt;
	}

	@Override
	public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
		// EncryptResponseBodyAdvice.setEncryptStatus(false);
		// Dynamic Settings Not Encrypted
		if (body == null) {
			return null;
		}
		response.getHeaders().setContentType(MediaType.TEXT_PLAIN);
		if (encrypt) {
			try {
				String content = mapper.writeValueAsString(body);
				String encodedData = SecureUtil.aes(secretKeyConfig.getAesKey().getBytes()).encryptHex(content);
				if (secretKeyConfig.isShowLog()) {
					log.info("返回前数据：{}，返回后数据：{}", content, encodedData);
				}
				return encodedData;
			} catch (Exception e) {
				log.error("Encrypted data exception", e);
			}
		}
		return body;
	}
}
