package incheon.product.geoview3d.traffic.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.function.Function;

/**
 * NDJSON(Newline Delimited JSON) 스트리밍 핸들러.
 * 대량의 데이터를 행 단위로 변환하여 OutputStream에 NDJSON 형식으로 출력한다.
 * 성능을 위해 500행마다 flush한다.
 *
 * @param <T> 입력 행 타입
 */
@Slf4j
public class NdjsonStreamHandler<T> {

    private static final int FLUSH_INTERVAL = 500;
    private static final byte[] NEWLINE = "\n".getBytes(StandardCharsets.UTF_8);

    private final OutputStream outputStream;
    private final Function<T, Object> transformer;
    private final ObjectMapper objectMapper;
    private int count;

    /**
     * @param outputStream 출력 스트림
     * @param transformer  행 데이터를 JSON 직렬화 대상 객체로 변환하는 함수
     */
    public NdjsonStreamHandler(OutputStream outputStream, Function<T, Object> transformer) {
        this.outputStream = outputStream;
        this.transformer = transformer;
        this.objectMapper = new ObjectMapper();
        this.count = 0;
    }

    /**
     * 단일 행을 NDJSON 형식으로 출력한다.
     *
     * @param row 행 데이터
     * @throws IOException 출력 오류
     */
    public void handle(T row) throws IOException {
        Object transformed = transformer.apply(row);
        byte[] json = objectMapper.writeValueAsBytes(transformed);
        outputStream.write(json);
        outputStream.write(NEWLINE);
        count++;

        if (count % FLUSH_INTERVAL == 0) {
            outputStream.flush();
        }
    }

    /**
     * 스트리밍을 종료하고 잔여 데이터를 flush한다.
     *
     * @throws IOException 출력 오류
     */
    public void finish() throws IOException {
        outputStream.flush();
        log.debug("NdjsonStreamHandler finished: {} rows written", count);
    }
}
