package com.dexorder.flink.publisher;

import com.dexorder.proto.OHLC;
import com.dexorder.proto.OHLCBatch;
import com.dexorder.proto.OHLCBatchMetadata;
import org.apache.flink.api.common.serialization.DeserializationSchema;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Kafka deserializer for OHLCBatch protobuf messages.
 * Handles messages from ingestors with metadata and OHLC rows.
 */
public class OHLCBatchDeserializer implements DeserializationSchema<OHLCBatchWrapper> {
    private static final Logger LOG = LoggerFactory.getLogger(OHLCBatchDeserializer.class);
    private static final long serialVersionUID = 1L;

    private static final byte PROTOCOL_VERSION = 0x01;
    private static final byte MSG_TYPE_OHLC_BATCH = 0x0B;

    @Override
    public OHLCBatchWrapper deserialize(byte[] message) throws IOException {
        try {
            if (message.length < 2) {
                throw new IOException("Message too short: " + message.length + " bytes");
            }

            byte version = message[0];
            if (version != PROTOCOL_VERSION) {
                throw new IOException("Unsupported protocol version: " + version);
            }

            byte messageType = message[1];
            if (messageType != MSG_TYPE_OHLC_BATCH) {
                throw new IOException("Unexpected message type: 0x" + Integer.toHexString(messageType));
            }

            byte[] protoPayload = new byte[message.length - 2];
            System.arraycopy(message, 2, protoPayload, 0, protoPayload.length);

            OHLCBatchWrapper wrapper = parseOHLCBatch(protoPayload);

            LOG.debug("Deserialized OHLCBatch: request_id={}, rows={}",
                    wrapper.getRequestId(), wrapper.getRowCount());

            return wrapper;

        } catch (Exception e) {
            LOG.error("Failed to deserialize OHLCBatch", e);
            throw new IOException("Failed to deserialize OHLCBatch", e);
        }
    }

    private OHLCBatchWrapper parseOHLCBatch(byte[] payload) throws IOException {
        OHLCBatch batch = OHLCBatch.parseFrom(payload);
        OHLCBatchMetadata meta = batch.getMetadata();

        List<OHLCBatchWrapper.OHLCRow> rows = new ArrayList<>(batch.getRowsCount());
        for (OHLC row : batch.getRowsList()) {
            rows.add(new OHLCBatchWrapper.OHLCRow(
                    row.getTimestamp(),
                    row.getTicker(),
                    row.getOpen(),
                    row.getHigh(),
                    row.getLow(),
                    row.getClose(),
                    row.hasVolume() ? row.getVolume()  : null
            ));
        }

        String status = meta.getStatus();
        if (status == null || status.isEmpty()) {
            status = "OK";
        }

        return new OHLCBatchWrapper(
                meta.getRequestId(),
                meta.hasClientId() ? meta.getClientId() : null,
                meta.getTicker(),
                meta.getPeriodSeconds(),
                meta.getStartTime(),
                meta.getEndTime(),
                status,
                meta.hasErrorMessage() ? meta.getErrorMessage() : null,
                rows,
                meta.getIsLastPage()
        );
    }

    @Override
    public boolean isEndOfStream(OHLCBatchWrapper nextElement) {
        return false;
    }

    @Override
    public TypeInformation<OHLCBatchWrapper> getProducedType() {
        return TypeInformation.of(OHLCBatchWrapper.class);
    }
}
