package com.cameleer.server.core.search;

import java.util.regex.Pattern;

/**
 * Structured attribute filter for execution search.
 * <p>
 * Value semantics:
 * <ul>
 *   <li>{@code value == null} or blank -> key-exists check</li>
 *   <li>{@code value} contains {@code *} -> wildcard match (translated to SQL LIKE pattern)</li>
 *   <li>otherwise -> exact match</li>
 * </ul>
 * <p>
 * Keys must match {@code ^[a-zA-Z0-9._-]+$} — they are later inlined into
 * ClickHouse SQL via {@code JSONExtractString}, which does not accept a
 * parameter placeholder for the JSON path. Values are always parameter-bound.
 */
public record AttributeFilter(String key, String value) {

    private static final Pattern KEY_PATTERN = Pattern.compile("^[a-zA-Z0-9._-]+$");

    public AttributeFilter {
        if (key == null || !KEY_PATTERN.matcher(key).matches()) {
            throw new IllegalArgumentException(
                    "Invalid attribute key: must match " + KEY_PATTERN.pattern() + ", got: " + key);
        }
        if (value != null && value.isBlank()) {
            value = null;
        }
    }

    public boolean isKeyOnly() {
        return value == null;
    }

    public boolean isWildcard() {
        return value != null && value.indexOf('*') >= 0;
    }

    /**
     * Returns a SQL LIKE pattern for wildcard matches with {@code %} / {@code _} / {@code \}
     * in the source value escaped, or {@code null} for exact / key-only filters.
     */
    public String toLikePattern() {
        if (!isWildcard()) return null;
        StringBuilder sb = new StringBuilder(value.length() + 4);
        for (int i = 0; i < value.length(); i++) {
            char c = value.charAt(i);
            switch (c) {
                case '\\' -> sb.append("\\\\");
                case '%' -> sb.append("\\%");
                case '_' -> sb.append("\\_");
                case '*' -> sb.append('%');
                default -> sb.append(c);
            }
        }
        return sb.toString();
    }
}
