package net.knarcraft.paidsigns.command;

import net.knarcraft.paidsigns.PaidSigns;
import net.knarcraft.paidsigns.container.PaidSign;
import net.knarcraft.paidsigns.property.PaidSignConditionProperty;
import net.knarcraft.paidsigns.property.PaidSignProperty;
import net.knarcraft.paidsigns.utility.TabCompleteHelper;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The tab completer for the edit paid sign command
 */
public class EditTabCompleter extends TokenizedTabCompleter {

    private static Map<PaidSignProperty, List<String>> propertyExampleValues;
    private static Map<PaidSignConditionProperty, List<String>> conditionPropertyExampleValues;

    @Nullable
    @Override
    public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
                                      @NotNull String[] args) {
        super.onTabComplete(sender, command, label, args);
        if (propertyExampleValues == null) {
            initializePropertyExampleValues();
            initializeConditionPropertyExampleValues();
        }

        if (argumentSize == 1) {
            return TabCompleteHelper.filterMatchingStartsWith(TabCompleteHelper.getPaidSignNames(), arguments.get(0));
        } else if (argumentSize >= 2) {
            PaidSign sign = PaidSigns.getInstance().getSignManager().getPaidSign(arguments.get(0));
            if (sign != null) {
                return tabCompleteForSign(sign);
            }
        }
        return new ArrayList<>();
    }

    /**
     * Returns tab completions for the given, non-null sign
     *
     * @param sign <p>The sign to tab complete for</p>
     * @return <p>The tab complete options to give to users</p>
     */
    private List<String> tabCompleteForSign(@NotNull PaidSign sign) {
        if (argumentSize == 2) {
            List<String> conditions = getAvailableSignConditions(sign);
            conditions.addAll(getPaidSignProperties());
            return TabCompleteHelper.filterMatchingStartsWith(conditions, arguments.get(1));
        } else if (argumentSize >= 3) {
            try {
                return tabCompleteSignLine(sign);
            } catch (NumberFormatException exception) {
                if (argumentSize == 3) {
                    return tabCompleteProperty();
                }
            }
        }
        return new ArrayList<>();
    }

    /**
     * Returns tab completions for the selected sign line
     *
     * @param sign <p>The paid sign the line belongs to</p>
     * @return <p>The tab complete options to give to users</p>
     */
    private List<String> tabCompleteSignLine(@NotNull PaidSign sign) {
        short signLine = (short) (Short.parseShort(arguments.get(1)) - 1);
        //Refuse to autocomplete if invalid input is given
        if (signLine < 0 || signLine > 3 || sign.getConditions().get(signLine) == null) {
            return new ArrayList<>();
        } else if (argumentSize == 3) {
            return TabCompleteHelper.filterMatchingStartsWith(getPaidSignConditionProperties(), arguments.get(2));
        } else if (argumentSize == 4) {
            PaidSignConditionProperty property = PaidSignConditionProperty.getFromString(arguments.get(2));
            if (property != null) {
                return TabCompleteHelper.filterMatchingStartsWith(conditionPropertyExampleValues.get(property),
                        arguments.get(3));
            }
        }
        return new ArrayList<>();
    }

    /**
     * Returns tab completions for the selected property
     *
     * @return <p>The tab complete options to give to users</p>
     */
    private List<String> tabCompleteProperty() {
        PaidSignProperty paidSignProperty = PaidSignProperty.getFromString(arguments.get(1));
        if (paidSignProperty != null) {
            if (paidSignProperty == PaidSignProperty.PERMISSION) {
                return TabCompleteHelper.tabCompletePermission(arguments.get(2));
            } else {
                return TabCompleteHelper.filterMatchingStartsWith(propertyExampleValues.get(paidSignProperty),
                        arguments.get(2));
            }
        } else {
            return new ArrayList<>();
        }
    }

    /**
     * Gets all paid sign condition properties
     *
     * @return <p>All paid sign condition properties</p>
     */
    private List<String> getPaidSignConditionProperties() {
        List<String> properties = new ArrayList<>();
        for (PaidSignConditionProperty property : PaidSignConditionProperty.values()) {
            properties.add(property.getStringRepresentation());
        }
        return properties;
    }

    /**
     * Gets all paid sign properties
     *
     * @return <p>All paid sign properties</p>
     */
    private List<String> getPaidSignProperties() {
        List<String> properties = new ArrayList<>();
        for (PaidSignProperty property : PaidSignProperty.values()) {
            properties.add(property.getStringRepresentation());
        }
        return properties;
    }

    /**
     * Gets all sign conditions available for the given sign
     *
     * @param sign <p>The sign to get available sign conditions for</p>
     * @return <p>The available sign conditions</p>
     */
    private List<String> getAvailableSignConditions(PaidSign sign) {
        List<String> availableConditions = new ArrayList<>();
        for (Short signLine : sign.getConditions().keySet()) {
            availableConditions.add(String.valueOf(signLine + 1));
        }
        return availableConditions;
    }

    /**
     * Initializes the map for paid sign property example tab completions
     */
    private void initializePropertyExampleValues() {
        propertyExampleValues = new HashMap<>();
        propertyExampleValues.put(PaidSignProperty.COST, TabCompleteHelper.getCosts());
        propertyExampleValues.put(PaidSignProperty.NAME, TabCompleteHelper.getPaidSignNames());
        propertyExampleValues.put(PaidSignProperty.IGNORE_CASE, TabCompleteHelper.getOptionStates());
        propertyExampleValues.put(PaidSignProperty.IGNORE_COLOR, TabCompleteHelper.getOptionStates());
        propertyExampleValues.put(PaidSignProperty.MATCH_ANY_CONDITION, TabCompleteHelper.getBooleans());
    }

    /**
     * Initializes the map for paid sign condition property example tab completions
     */
    private void initializeConditionPropertyExampleValues() {
        conditionPropertyExampleValues = new HashMap<>();
        conditionPropertyExampleValues.put(PaidSignConditionProperty.STRING_TO_MATCH,
                TabCompleteHelper.getExampleConditionStrings());
        conditionPropertyExampleValues.put(PaidSignConditionProperty.IGNORE_COLOR, TabCompleteHelper.getOptionStates());
        conditionPropertyExampleValues.put(PaidSignConditionProperty.IGNORE_CASE, TabCompleteHelper.getOptionStates());
        conditionPropertyExampleValues.put(PaidSignConditionProperty.EXECUTE_REG_EX, TabCompleteHelper.getBooleans());
    }

}