package com.njcn.rdms.framework.encrypt.core.filter;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import cn.hutool.crypto.asymmetric.AsymmetricDecryptor;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.symmetric.SymmetricDecryptor;
import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;

/**
 * 解密请求 {@link HttpServletRequestWrapper} 实现类
 *
 * @author hongawen
 */
public class ApiDecryptRequestWrapper extends HttpServletRequestWrapper {

    private final byte[] body;

    public ApiDecryptRequestWrapper(HttpServletRequest request,
                                    ObjectMapper objectMapper,
                                    List<String> requestFields,
                                    SymmetricDecryptor symmetricDecryptor,
                                    AsymmetricDecryptor asymmetricDecryptor) throws IOException {
        super(request);
        if (CollUtil.isEmpty(requestFields)) {
            throw invalidParamException("请求解密失败，请刷新页面后重试");
        }
        String requestBody = StrUtil.utf8Str(IoUtil.readBytes(request.getInputStream(), false));
        if (StrUtil.isBlank(requestBody)) {
            throw invalidParamException("请求解密失败，请刷新页面后重试");
        }

        JsonNode requestJson;
        try {
            requestJson = objectMapper.readTree(requestBody);
        } catch (Exception ex) {
            throw invalidParamException("请求解密失败，请刷新页面后重试");
        }
        if (!(requestJson instanceof ObjectNode requestObject)) {
            throw invalidParamException("请求解密失败，请刷新页面后重试");
        }

        for (String requestField : requestFields) {
            JsonNode fieldNode = requestObject.get(requestField);
            if (fieldNode == null || fieldNode.isNull() || !fieldNode.isTextual() || StrUtil.isBlank(fieldNode.asText())) {
                throw invalidParamException("请求解密失败，请刷新页面后重试");
            }
            byte[] decryptedBytes = symmetricDecryptor != null
                    ? symmetricDecryptor.decrypt(fieldNode.asText())
                    : asymmetricDecryptor.decrypt(fieldNode.asText(), KeyType.PrivateKey);
            requestObject.put(requestField, StrUtil.utf8Str(decryptedBytes));
        }

        body = objectMapper.writeValueAsBytes(requestObject);
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }

    @Override
    public int getContentLength() {
        return body.length;
    }

    @Override
    public long getContentLengthLong() {
        return body.length;
    }

    @Override
    public ServletInputStream getInputStream() {
        ByteArrayInputStream stream = new ByteArrayInputStream(body);
        return new ServletInputStream() {

            @Override
            public int read() {
                return stream.read();
            }

            @Override
            public int available() {
                return body.length;
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }

        };
    }
}
