package com.r35157.nenjim.service.journal.exception;

import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;

/** Reports a structural, semantic, or chain error in a Journal update. */
public final class InvalidJournalException extends IllegalArgumentException {
    private final String reason;
    private final Optional<String> sourceName;
    private final OptionalInt lineNumber;

    public InvalidJournalException(String reason) {
        this(null, 0, reason, null);
    }

    public InvalidJournalException(String sourceName, int lineNumber, String reason) {
        this(sourceName, lineNumber, reason, null);
    }

    public InvalidJournalException(String sourceName, int lineNumber, String reason, Throwable cause) {
        super(formatMessage(sourceName, lineNumber, reason), cause);
        this.reason = Objects.requireNonNull(reason, "reason");
        this.sourceName = sourceName == null || sourceName.isBlank()
                ? Optional.empty() : Optional.of(sourceName);
        if (lineNumber < 0) {
            throw new IllegalArgumentException("lineNumber cannot be negative");
        }
        this.lineNumber = lineNumber == 0 ? OptionalInt.empty() : OptionalInt.of(lineNumber);
    }

    public String reason() {
        return reason;
    }

    public Optional<String> sourceName() {
        return sourceName;
    }

    public OptionalInt lineNumber() {
        return lineNumber;
    }

    private static String formatMessage(String sourceName, int lineNumber, String reason) {
        Objects.requireNonNull(reason, "reason");
        String location = sourceName == null || sourceName.isBlank() ? "Journal" : sourceName;
        if (lineNumber > 0) location += ":" + lineNumber;
        return location + ": " + reason;
    }
}
