package com.dexorder.flink.publisher;

import java.io.Serializable;
import java.util.List;

/**
 * Wrapper for OHLCBatch protobuf message.
 * Contains metadata and OHLC rows from ingestor.
 */
public class OHLCBatchWrapper implements Serializable {
    private static final long serialVersionUID = 1L;

    private final String requestId;
    private final String clientId;
    private final String ticker;
    private final int periodSeconds;
    private final long startTime;
    private final long endTime;
    private final String status; // OK, NOT_FOUND, ERROR
    private final String errorMessage;
    private final List<OHLCRow> rows;
    private final boolean isLastPage;

    public OHLCBatchWrapper(
            String requestId,
            String clientId,
            String ticker,
            int periodSeconds,
            long startTime,
            long endTime,
            String status,
            String errorMessage,
            List<OHLCRow> rows,
            boolean isLastPage
    ) {
        this.requestId = requestId;
        this.clientId = clientId;
        this.ticker = ticker;
        this.periodSeconds = periodSeconds;
        this.startTime = startTime;
        this.endTime = endTime;
        this.status = status;
        this.errorMessage = errorMessage;
        this.rows = rows;
        this.isLastPage = isLastPage;
    }

    public String getRequestId() {
        return requestId;
    }

    public String getClientId() {
        return clientId;
    }

    public String getTicker() {
        return ticker;
    }

    public int getPeriodSeconds() {
        return periodSeconds;
    }

    public long getStartTime() {
        return startTime;
    }

    public long getEndTime() {
        return endTime;
    }

    public String getStatus() {
        return status;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public List<OHLCRow> getRows() {
        return rows;
    }

    public int getRowCount() {
        return rows != null ? rows.size() : 0;
    }

    public boolean hasError() {
        return "ERROR".equals(status);
    }

    public boolean isNotFound() {
        return "NOT_FOUND".equals(status);
    }

    public boolean isOk() {
        return "OK".equals(status);
    }

    public boolean isLastPage() {
        return isLastPage;
    }

    @Override
    public String toString() {
        return "OHLCBatchWrapper{" +
                "requestId='" + requestId + '\'' +
                ", clientId='" + clientId + '\'' +
                ", ticker='" + ticker + '\'' +
                ", periodSeconds=" + periodSeconds +
                ", status='" + status + '\'' +
                ", rowCount=" + getRowCount() +
                ", isLastPage=" + isLastPage +
                '}';
    }

    /**
     * Single OHLC row. open/high/low/close/volume are nullable to support gap bars
     * (periods where no trades occurred).
     */
    public static class OHLCRow implements Serializable {
        private static final long serialVersionUID = 1L;

        private final long timestamp;
        private final String ticker;
        private final Long open;   // null for gap bars
        private final Long high;   // null for gap bars
        private final Long low;    // null for gap bars
        private final Long close;  // null for gap bars
        private final Long volume; // null when no volume data

        public OHLCRow(long timestamp, String ticker, Long open, Long high,
                      Long low, Long close, Long volume) {
            this.timestamp = timestamp;
            this.ticker = ticker;
            this.open = open;
            this.high = high;
            this.low = low;
            this.close = close;
            this.volume = volume;
        }

        public long getTimestamp() {
            return timestamp;
        }

        public String getTicker() {
            return ticker;
        }

        public Long getOpen() {
            return open;
        }

        public Long getHigh() {
            return high;
        }

        public Long getLow() {
            return low;
        }

        public Long getClose() {
            return close;
        }

        public Long getVolume() {
            return volume;
        }

        public boolean isGapBar() {
            return open == null && high == null && low == null && close == null;
        }

        @Override
        public String toString() {
            return "OHLCRow{" +
                    "timestamp=" + timestamp +
                    ", ticker='" + ticker + '\'' +
                    (isGapBar() ? ", gap=true" :
                        ", open=" + open + ", high=" + high + ", low=" + low + ", close=" + close) +
                    ", volume=" + volume +
                    '}';
        }
    }
}
