package de.renew.navigator.models;

import java.util.ArrayList;
import java.util.List;

import de.renew.util.StringUtil;

/**
 * Represents a filter for searching text based on defined matching rules.
 * A SearchFilter allows filtering strings by specifying match conditions (e.g., starts with, contains, ends with),
 * optionally considering case sensitivity.
 */
public final class SearchFilter {
    private final String _name;
    private final Type _type;
    private final List<String> _terms;
    private final boolean _caseSensitive;

    /**
     * @param name name of search filter
     * @param type type of search filter
     * @param caseSensitive if it should check the case
     * @param terms search terms
     */
    public SearchFilter(String name, Type type, boolean caseSensitive, String... terms) {
        this._name = name;
        this._type = type;
        this._caseSensitive = caseSensitive;
        this._terms = new ArrayList<>();

        if (terms != null) {
            for (String text : terms) {
                String tmp = StringUtil.trimToNull(text);
                if (tmp == null) {
                    continue;
                }
                this._terms.add(tmp);
            }
        }
    }

    /**
     * Matches a string with the search filter.
     *
     * @param check string to check
     * @return true, if the string matches
     */
    public boolean match(final String check) {
        if (this._terms.isEmpty()) {
            return true;
        }

        String toCheck = StringUtil.trimToNull(check);
        if (toCheck == null) {
            return true;
        }

        // Check all
        final String checkText = formatCheckText(toCheck);

        for (String term : _terms) {
            return doesTermMatchCondition(term, checkText);
        }

        return false;
    }

    private String formatCheckText(String toCheck) {
        return _caseSensitive ? toCheck : toCheck.toLowerCase();
    }

    private boolean doesTermMatchCondition(String term, String checkText) {
        final String termText = formatCheckText(term);
        if (isStartsWith() && checkText.startsWith(termText)) {
            return true;
        }

        if (isContains() && checkText.contains(termText)) {
            return true;
        }
        return isEndsWith() && checkText.endsWith(termText);
    }

    /**
     * Validates the search filter.
     *
     * @return true, if valid.
     */
    public boolean isValid() {
        for (String text : _terms) {
            if (text != null && !text.isEmpty()) {
                return true;
            }
        }
        return false;
    }

    private boolean isEndsWith() {
        return _type == Type.ENDS_WITH;
    }

    private boolean isStartsWith() {
        return _type == Type.STARTS_WITH;
    }

    private boolean isContains() {
        return _type == Type.CONTAINS;
    }

    /**
     * Checks whether the filter is case-sensitive.
     *
     * @return true, if the filter is case-sensitive.
     */
    public boolean isCaseSensitive() {
        return _caseSensitive;
    }

    /**
     * This is a getter which gets the type of the filter.
     *
     * @return _type the Type of the filter.
     */
    public Type getType() {
        return _type;
    }

    /**
     * This is a getter which gets the terms of the filter.
     *
     * @return _terms the List of Strings of the terms of the filter.
     */
    public List<String> getTerms() {
        return _terms;
    }

    /**
     * This is a getter which gets the name of the filter.
     *
     * @return _name the String of the name of the filter.
     */
    public String getName() {
        return _name;
    }

    /**
     * Type of the search filter.
     */
    public enum Type {
        /**
         * Represents a type of search filter where the search term must match
         * the beginning of the target string.
         */
        STARTS_WITH,
        /**
         * Represents a search filter type where the search term can match
         * any part of the target string, not limited to the start or end.
         */
        CONTAINS,
        /**
         * Represents a type of search filter where the search term must match
         * the end of the target string.
         */
        ENDS_WITH
    }
}