package com.dexorder.flink.publisher;

import com.dexorder.proto.HistoryReadyNotification;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zeromq.SocketType;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;

/**
 * Pushes HistoryReadyNotification protobuf messages to the job manager's notification forwarder.
 *
 * Uses ZMQ PUSH socket connecting to the job manager's PULL socket.
 * The job manager's HistoryNotificationForwarder receives and republishes via MARKET_DATA_PUB.
 * Topic format: "RESPONSE:{client_id}" or "HISTORY_READY:{request_id}"
 */
public class HistoryNotificationPublisher implements AutoCloseable {
    private static final Logger LOG = LoggerFactory.getLogger(HistoryNotificationPublisher.class);
    private static final byte PROTOCOL_VERSION = 0x01;
    private static final byte MSG_TYPE_HISTORY_READY = 0x12;

    private final ZContext context;
    private final ZMQ.Socket publishSocket;

    public HistoryNotificationPublisher(String jobManagerPullEndpoint) {
        this.context = new ZContext();
        this.publishSocket = context.createSocket(SocketType.PUSH);

        publishSocket.setLinger(1000);
        publishSocket.setSndHWM(10000);
        publishSocket.connect(jobManagerPullEndpoint);

        LOG.info("HistoryNotificationPublisher connected PUSH to {}", jobManagerPullEndpoint);
    }

    public void publishHistoryReady(
            String requestId,
            String clientId,
            String ticker,
            int periodSeconds,
            long startTime,
            long endTime,
            String icebergNamespace,
            String icebergTable,
            int rowCount
    ) {
        String topic = clientId != null ? "RESPONSE:" + clientId : "HISTORY_READY:" + requestId;

        HistoryReadyNotification notification = HistoryReadyNotification.newBuilder()
                .setRequestId(requestId)
                .setTicker(ticker)
                .setPeriodSeconds(periodSeconds)
                .setStartTime(startTime)
                .setEndTime(endTime)
                .setStatus(HistoryReadyNotification.NotificationStatus.OK)
                .setIcebergNamespace(icebergNamespace)
                .setIcebergTable(icebergTable)
                .setRowCount(rowCount)
                .setCompletedAt(System.currentTimeMillis() * 1000)
                .build();

        publish(topic, notification.toByteArray());
        LOG.info("Published HistoryReadyNotification: topic={}, request_id={}, rows={}", topic, requestId, rowCount);
    }

    public void publishError(
            String requestId,
            String clientId,
            String ticker,
            int periodSeconds,
            long startTime,
            long endTime,
            String errorMessage
    ) {
        String topic = clientId != null ? "RESPONSE:" + clientId : "HISTORY_READY:" + requestId;

        HistoryReadyNotification.Builder builder = HistoryReadyNotification.newBuilder()
                .setRequestId(requestId)
                .setTicker(ticker)
                .setPeriodSeconds(periodSeconds)
                .setStartTime(startTime)
                .setEndTime(endTime)
                .setStatus(HistoryReadyNotification.NotificationStatus.ERROR);
        if (errorMessage != null) {
            builder.setErrorMessage(errorMessage);
        }

        publish(topic, builder.build().toByteArray());
        LOG.error("Published error notification: topic={}, request_id={}, error={}", topic, requestId, errorMessage);
    }

    public void publishNotFound(
            String requestId,
            String clientId,
            String ticker,
            int periodSeconds,
            long startTime,
            long endTime
    ) {
        String topic = clientId != null ? "RESPONSE:" + clientId : "HISTORY_READY:" + requestId;

        HistoryReadyNotification notification = HistoryReadyNotification.newBuilder()
                .setRequestId(requestId)
                .setTicker(ticker)
                .setPeriodSeconds(periodSeconds)
                .setStartTime(startTime)
                .setEndTime(endTime)
                .setStatus(HistoryReadyNotification.NotificationStatus.NOT_FOUND)
                .build();

        publish(topic, notification.toByteArray());
        LOG.info("Published not-found notification: topic={}, request_id={}", topic, requestId);
    }

    private void publish(String topic, byte[] protoPayload) {
        byte[] messageFrame = new byte[1 + protoPayload.length];
        messageFrame[0] = MSG_TYPE_HISTORY_READY;
        System.arraycopy(protoPayload, 0, messageFrame, 1, protoPayload.length);

        publishSocket.sendMore(topic);
        publishSocket.sendMore(new byte[]{PROTOCOL_VERSION});
        publishSocket.send(messageFrame, 0);
    }

    @Override
    public void close() {
        if (publishSocket != null) publishSocket.close();
        if (context != null) context.close();
    }
}
