package com.dexorder.flink.publisher;

import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.functions.ProcessFunction;
import org.apache.flink.util.Collector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Flink function that processes OHLCBatch messages and publishes notifications
 * after data is written to Iceberg.
 *
 * This function:
 * 1. Receives OHLCBatch messages with metadata and rows
 * 2. Writes rows to Iceberg (pass through to sink)
 * 3. Publishes HistoryReadyNotification immediately after batch completes
 *
 * Note: Each OHLCBatch is a complete unit - one batch = one notification
 */
public class HistoryNotificationFunction extends ProcessFunction<OHLCBatchWrapper, OHLCBatchWrapper> {
    private static final Logger LOG = LoggerFactory.getLogger(HistoryNotificationFunction.class);

    private final String notificationEndpoint;
    private final String icebergNamespace;
    private final String icebergTablePrefix;

    private transient HistoryNotificationPublisher publisher;

    public HistoryNotificationFunction(
            String notificationEndpoint,
            String icebergNamespace,
            String icebergTablePrefix
    ) {
        this.notificationEndpoint = notificationEndpoint;
        this.icebergNamespace = icebergNamespace;
        this.icebergTablePrefix = icebergTablePrefix;
    }

    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);

        // Initialize ZMQ publisher
        publisher = new HistoryNotificationPublisher(notificationEndpoint);
        LOG.info("Initialized HistoryNotificationPublisher on {}", notificationEndpoint);
    }

    @Override
    public void processElement(
            OHLCBatchWrapper batch,
            Context context,
            Collector<OHLCBatchWrapper> out
    ) throws Exception {

        // Pass through the batch for Iceberg sink
        out.collect(batch);

        String requestId = batch.getRequestId();
        String clientId = batch.getClientId();
        String ticker = batch.getTicker();
        int periodSeconds = batch.getPeriodSeconds();
        long startTime = batch.getStartTime();
        long endTime = batch.getEndTime();
        String status = batch.getStatus();
        int rowCount = batch.getRowCount();

        LOG.info("Processing OHLCBatch: request_id={}, status={}, rows={}",
                requestId, status, rowCount);

        // Determine Iceberg table name based on period
        String tableName = getIcebergTableName(ticker, periodSeconds);

        // Publish notification based on status
        if ("ERROR".equals(status)) {
            // Error during fetch
            publisher.publishError(
                    requestId,
                    clientId,
                    ticker,
                    periodSeconds,
                    startTime,
                    endTime,
                    batch.getErrorMessage()
            );
        } else if ("NOT_FOUND".equals(status) || rowCount == 0) {
            // No data available
            publisher.publishNotFound(
                    requestId,
                    clientId,
                    ticker,
                    periodSeconds,
                    startTime,
                    endTime
            );
        } else {
            // Success - data available
            publisher.publishHistoryReady(
                    requestId,
                    clientId,
                    ticker,
                    periodSeconds,
                    startTime,
                    endTime,
                    icebergNamespace,
                    tableName,
                    rowCount
            );
        }

        LOG.info("Published notification for request_id={}", requestId);
    }

    @Override
    public void close() throws Exception {
        super.close();
        if (publisher != null) {
            publisher.close();
        }
    }

    private String getIcebergTableName(String ticker, int periodSeconds) {
        // Extract exchange from ticker (e.g., "BINANCE:BTC/USDT" -> "binance")
        String exchange = ticker.split(":")[0].toLowerCase();

        // Convert period to human-readable format
        String period;
        if (periodSeconds < 3600) {
            period = (periodSeconds / 60) + "m";
        } else if (periodSeconds < 86400) {
            period = (periodSeconds / 3600) + "h";
        } else {
            period = (periodSeconds / 86400) + "d";
        }

        return String.format("%s_ohlc_%s_%s", icebergTablePrefix, exchange, period);
    }
}
