package com.kexue.skills.interceptor;

import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 可捕获响应体的 HttpServletResponse 包装类
 */
public class CachedBodyHttpServletResponse extends HttpServletResponseWrapper {
    
    private final ByteArrayOutputStream cachedBody = new ByteArrayOutputStream();
    private ServletOutputStream outputStream;
    private PrintWriter writer;
    
    public CachedBodyHttpServletResponse(HttpServletResponse response) {
        super(response);
    }
    
    @Override
    public ServletOutputStream getOutputStream() throws IOException {
        if (outputStream == null) {
            outputStream = new CachedBodyServletOutputStream(super.getOutputStream(), cachedBody);
        }
        return outputStream;
    }
    
    @Override
    public PrintWriter getWriter() throws IOException {
        if (writer == null) {
            writer = new PrintWriter(getOutputStream(), true);
        }
        return writer;
    }
    
    @Override
    public void flushBuffer() throws IOException {
        if (writer != null) {
            writer.flush();
        }
        if (outputStream != null) {
            outputStream.flush();
        }
        super.flushBuffer();
    }
    
    public String getCachedBodyString() {
        return cachedBody.toString();
    }
    
    private static class CachedBodyServletOutputStream extends ServletOutputStream {
        
        private final ServletOutputStream outputStream;
        private final ByteArrayOutputStream cachedBody;
        
        public CachedBodyServletOutputStream(ServletOutputStream outputStream, ByteArrayOutputStream cachedBody) {
            this.outputStream = outputStream;
            this.cachedBody = cachedBody;
        }
        
        @Override
        public boolean isReady() {
            return outputStream.isReady();
        }
        
        @Override
        public void setWriteListener(WriteListener listener) {
            outputStream.setWriteListener(listener);
        }
        
        @Override
        public void write(int b) throws IOException {
            outputStream.write(b);
            cachedBody.write(b);
        }
        
        @Override
        public void write(byte[] b) throws IOException {
            outputStream.write(b);
            cachedBody.write(b);
        }
        
        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            outputStream.write(b, off, len);
            cachedBody.write(b, off, len);
        }
    }
}
