package org.jabref.model;

import java.util.Objects;

import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.field.Field;

import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;

/// This class is used in the instance of a field being modified, removed or added.
@NullMarked
public class FieldChange {

    private final BibEntry entry;
    private final Field field;
    @Nullable private final String oldValue;
    @Nullable private final String newValue;

    public FieldChange(BibEntry entry, Field field, @Nullable String oldValue, @Nullable String newValue) {
        this.entry = entry;
        this.field = field;
        this.oldValue = oldValue;
        this.newValue = newValue;
    }

    public BibEntry getEntry() {
        return this.entry;
    }

    public Field getField() {
        return this.field;
    }

    public @Nullable String getOldValue() {
        return this.oldValue;
    }

    public @Nullable String getNewValue() {
        return this.newValue;
    }

    @Override
    public int hashCode() {
        return Objects.hash(entry, field, newValue, oldValue);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof FieldChange other) {
            // Entry never null
            if (!entry.equals(other.entry)) {
                return false;
            }

            // Field never null
            if (!field.equals(other.field)) {
                return false;
            }

            if (newValue == null) {
                if (other.newValue != null) {
                    return false;
                }
            } else if (!newValue.equals(other.newValue)) {
                return false;
            }

            if (oldValue == null) {
                return other.oldValue == null;
            } else {
                return oldValue.equals(other.oldValue);
            }
        }
        return false;
    }

    @Override
    public String toString() {
        return "FieldChange [entry=" + entry.getCitationKey().orElse("") + ", field=" + field + ", oldValue="
                + oldValue + ", newValue=" + newValue + "]";
    }
}
