package net.knarcraft.blacksmith.util;

import net.knarcraft.blacksmith.config.SettingValueType;
import org.bukkit.command.CommandSender;

import static net.knarcraft.blacksmith.util.MessageFormatter.displayErrorMessage;

/**
 * A helper class for validating a value's type
 */
public final class TypeValidationHelper {

    private TypeValidationHelper() {

    }

    /**
     * Gets whether the given value is valid for the given value type
     *
     * @param valueType <p>The value type required</p>
     * @param value     <p>The value given</p>
     * @param sender    <p>The command sender to use for printing error messages</p>
     * @return <p>True if the value is valid</p>
     */
    public static boolean isValid(SettingValueType valueType, Object value, CommandSender sender) {
        try {
            return switch (valueType) {
                case POSITIVE_DOUBLE -> isPositiveDouble(value, sender);
                case STRING -> isNonEmptyString(value, sender);
                case POSITIVE_INTEGER -> isPositiveInteger(value, sender);
                case PERCENTAGE -> isPercentage(value, sender);
                case BOOLEAN -> true;
                case STRING_LIST -> isStringList(value, sender);
                case MATERIAL, ENCHANTMENT -> false;
            };
        } catch (ClassCastException exception) {
            //This error signifies that an object is not a string, and of the wrong class
            return false;
        }
    }

    /**
     * Checks whether the given value is a string list
     *
     * @param value  <p>The value to check</p>
     * @param sender <p>The command sender to use for printing error messages</p>
     * @return <p>True if the value is a string list</p>
     */
    private static boolean isStringList(Object value, CommandSender sender) {
        boolean isStringList = value instanceof String[] || value instanceof String;
        if (!isStringList && sender != null) {
            displayErrorMessage(sender, "A string list is required!");
        }
        return isStringList;
    }

    /**
     * Checks whether the given value is a valid percentage
     *
     * @param value  <p>The value to check</p>
     * @param sender <p>The command sender to use for printing error messages</p>
     * @return <p>True if the value is a percentage</p>
     */
    private static boolean isPercentage(Object value, CommandSender sender) {
        try {
            int intValue = ConfigHelper.asInt(value);
            return intValue > 0 && intValue <= 100;
        } catch (NumberFormatException | NullPointerException exception) {
            if (sender != null) {
                displayErrorMessage(sender, "You specified a value which isn't between 0 and 100!");
            }
            return false;
        }
    }

    /**
     * Checks whether the given value is a non-empty string
     *
     * @param value  <p>The value to check</p>
     * @param sender <p>The command sender to use for printing error messages</p>
     * @return <p>True if the value is a non-empty string</p>
     */
    private static boolean isNonEmptyString(Object value, CommandSender sender) {
        boolean isString = value instanceof String string && !string.strip().isEmpty();
        if (!isString && sender != null) {
            displayErrorMessage(sender, "A non-empty string is required!");
        }
        return isString;
    }

    /**
     * Checks whether the given value is a positive double
     *
     * @param value  <p>The value to check</p>
     * @param sender <p>The command sender to use for printing error messages</p>
     * @return <p>True if the value is a positive double</p>
     */
    private static boolean isPositiveDouble(Object value, CommandSender sender) {
        try {
            return ConfigHelper.asDouble(value) > 0.0;
        } catch (NumberFormatException | NullPointerException exception) {
            if (sender != null) {
                displayErrorMessage(sender, "You specified a value which isn't a positive double!");
            }
            return false;
        }
    }

    /**
     * Checks whether the given value is a positive integer
     *
     * @param value  <p>The value to check</p>
     * @param sender <p>The command sender to use for printing error messages</p>
     * @return <p>True if the value is a positive integer</p>
     */
    private static boolean isPositiveInteger(Object value, CommandSender sender) {
        try {
            return ConfigHelper.asInt(value) > 0;
        } catch (NumberFormatException | NullPointerException exception) {
            if (sender != null) {
                displayErrorMessage(sender, "You specified a value which isn't a positive integer!");
            }
            return false;
        }
    }

}
