package io.github.js0ny.ilp_coursework.util;

import com.fasterxml.jackson.databind.JsonNode;

import java.math.BigDecimal;

/**
 * Comparator for attribute values in {@code JsonNode}.
 *
 * <p>This is a helper for dynamic querying.
 */
public class AttrComparator {
    /**
     * Helper for dynamic querying, to compare the json value with given value in {@code String}.
     *
     * @param node The {@code JsonNode} to be compared
     * @param attrVal The Value passed, in {@code String}
     * @param op The comparison operator
     * @return {@code true} if given values are equal, otherwise false.
     */
    public static boolean isValueMatched(JsonNode node, String attrVal, AttrOperator op) {
        if (node.isTextual()) {
            return compareStrings(node.asText(), attrVal, op);
        } else if (node.isNumber()) {
            // return Double.compare(node.asDouble(), Double.parseDouble(attrVal)) == 0;
            return compareNumbers(node.decimalValue(), new BigDecimal(attrVal), op);
        } else if (node.isBoolean()) {
            return compareBooleans(node.asBoolean(), Boolean.parseBoolean(attrVal), op);
        } else {
            return false;
        }
    }

    private static boolean compareNumbers(BigDecimal nodeVal, BigDecimal attrVal, AttrOperator op) {
        int comparison = nodeVal.compareTo(attrVal);
        return switch (op) {
            case EQ -> comparison == 0;
            case GT -> comparison > 0;
            case LT -> comparison < 0;
            case NE -> comparison != 0;
        };
    }

    private static boolean compareStrings(String nodeVal, String attrVal, AttrOperator op) {
        return switch (op) {
            case EQ -> nodeVal.equals(attrVal);
            default -> !nodeVal.equals(attrVal);
                // case NE -> !nodeVal.equals(attrVal);
                // case GT -> !nodeVal.equals(attrVal);// > 0;
                // case LT -> !nodeVal.equals(attrVal);// < 0;
        };
    }

    private static boolean compareBooleans(boolean nodeVal, boolean attrVal, AttrOperator op) {
        return switch (op) {
            case EQ -> nodeVal == attrVal;
            default -> nodeVal != attrVal;
                // case NE -> nodeVal != attrVal;
                // case GT -> !nodeVal && attrVal; // false < true
                // case LT -> nodeVal && !attrVal; // true > false
        };
    }
}
