package com.usky.vpp.web.advice;

import com.usky.vpp.controller.un.UnDnController;
import com.usky.vpp.crypto.VppUnCryptoService;
import com.usky.vpp.util.VppUnCipherPayloadHelper;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;

/**
 * UN 调用 DN 被动接口时，解密国密请求体
 */
@ControllerAdvice(assignableTypes = UnDnController.class)
public class VppUnDnCryptoRequestAdvice extends RequestBodyAdviceAdapter {

    @Autowired
    private VppUnCryptoService cryptoService;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType,
                            Class<? extends HttpMessageConverter<?>> converterType) {
        if (isTokenRequest(methodParameter)) {
            return false;
        }
        return cryptoService.isAnyActive();
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
                                           Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        byte[] bodyBytes = StreamUtils.copyToByteArray(inputMessage.getBody());
        if (bodyBytes.length == 0) {
            return inputMessage;
        }
        String body = new String(bodyBytes, StandardCharsets.UTF_8).trim();
        if (body.startsWith("{")) {
            return new DecodedHttpInputMessage(inputMessage.getHeaders(), bodyBytes);
        }
        String sign = inputMessage.getHeaders().getFirst("X-Sign");
        if (!StringUtils.hasText(sign)) {
            throw new com.usky.common.core.exception.BusinessException("UN 请求缺少 X-Sign");
        }
        String cipherBase64 = VppUnCipherPayloadHelper.extractCipherPayload(body, objectMapper);
        String plain = cryptoService.decryptInboundWithAutoTenant(cipherBase64, sign);
        return new DecodedHttpInputMessage(inputMessage.getHeaders(), plain.getBytes(StandardCharsets.UTF_8));
    }

    private static boolean isTokenRequest(MethodParameter methodParameter) {
        return methodParameter.getMethod() != null
                && "tokenRequest".equals(methodParameter.getMethod().getName());
    }

    private static class DecodedHttpInputMessage implements HttpInputMessage {
        private final HttpHeaders headers;
        private final byte[] body;

        private DecodedHttpInputMessage(HttpHeaders headers, byte[] body) {
            this.headers = headers;
            this.body = body;
        }

        @Override
        public InputStream getBody() {
            return new ByteArrayInputStream(body);
        }

        @Override
        public HttpHeaders getHeaders() {
            return headers;
        }
    }
}
