package net.knarcraft.blacksmith.command;

import net.knarcraft.blacksmith.BlacksmithPlugin;
import net.knarcraft.blacksmith.config.GlobalSetting;
import net.knarcraft.blacksmith.config.GlobalSettings;
import net.knarcraft.blacksmith.config.NPCSetting;
import net.knarcraft.blacksmith.config.SettingValueType;
import net.knarcraft.blacksmith.manager.ItemType;
import net.knarcraft.blacksmith.manager.Message;
import net.knarcraft.blacksmith.util.InputParsingHelper;
import net.knarcraft.blacksmith.util.TypeValidationHelper;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.NotNull;

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

/**
 * The command used for changing global configuration options
 */
public class BlackSmithConfigCommand implements CommandExecutor {

    @Override
    public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
                             @NotNull String[] args) {
        if (args.length == 0) {
            return false;
        }

        String commandName = args[0];
        if (commandName.equalsIgnoreCase("reload")) {
            return new ReloadCommand().onCommand(sender, command, label, args);
        }
        GlobalSettings settings = BlacksmithPlugin.getInstance().getSettings();

        //Changing reforge-able items' default isn't recommended
        if (commandName.equalsIgnoreCase(NPCSetting.REFORGE_ABLE_ITEMS.getCommandName())) {
            displayErrorMessage(sender, "Changing reforge-able items globally will make every new " +
                    "blacksmith unable to re-forge anything not in the list, unless it's changed for the " +
                    "individual NPC. If you really want to change this, change it manually.");
            return false;
        }

        //Find which global setting the user has specified, if any
        GlobalSetting detectedGlobalSetting = null;
        for (GlobalSetting globalSetting : GlobalSetting.values()) {
            if (commandName.equalsIgnoreCase(globalSetting.getCommandName())) {
                detectedGlobalSetting = globalSetting;
                break;
            }
        }

        //Find which npc setting the user has specified, if any
        NPCSetting detectedNPCSetting = null;
        for (NPCSetting npcSetting : NPCSetting.values()) {
            if (commandName.equalsIgnoreCase(npcSetting.getCommandName())) {
                detectedNPCSetting = npcSetting;
                break;
            }
        }

        if (args.length == 1) {
            //TODO: See if there's a way to remove this duplication
            String rawValue;
            String correctCommandName;
            if (detectedGlobalSetting != null) {
                rawValue = String.valueOf(settings.getRawValue(detectedGlobalSetting));
                correctCommandName = detectedGlobalSetting.getCommandName();
            } else if (detectedNPCSetting != null) {
                rawValue = String.valueOf(settings.getRawValue(detectedNPCSetting));
                correctCommandName = detectedNPCSetting.getCommandName();
            } else {
                return false;
            }
            displaySuccessMessage(sender, Message.getCurrentValueMessage(correctCommandName, rawValue));
            sender.sendMessage("Raw value: " + rawValue.replace(ChatColor.COLOR_CHAR, '&'));
            return true;
        } else if (args.length == 2 && isSpecialCase(commandName)) {
            if (displaySpecialCaseValue(args[1], sender, detectedGlobalSetting, settings)) {
                return true;
            }
        }

        if (args.length == 3 && updateSpecialCase(settings, detectedGlobalSetting, args, sender)) {
            return true;
        }

        String newValue = args[1];
        if (detectedGlobalSetting != null) {
            settings.changeValue(detectedGlobalSetting, newValue);
            displaySuccessMessage(sender, Message.getValueChangedMessage(detectedGlobalSetting.getCommandName(), newValue));
            return true;
        } else if (detectedNPCSetting != null) {
            settings.changeValue(detectedNPCSetting, newValue);
            displaySuccessMessage(sender, Message.getValueChangedMessage(detectedNPCSetting.getNodeName(), newValue));
            return true;
        }
        return false;
    }

    /**
     * Displays the current value of a special-case configuration value
     *
     * @param selector <p>The selector specifying which material/enchantment to display information about</p>
     * @param sender   <p>The sender to display the value to</p>
     * @param setting  <p>The setting to display</p>
     * @param settings <p>The settings object to query</p>
     * @return <p>True if the value was successfully displayed</p>
     */
    private boolean displaySpecialCaseValue(String selector, CommandSender sender, GlobalSetting setting,
                                            GlobalSettings settings) {
        if (setting == GlobalSetting.BASE_PRICE || setting == GlobalSetting.PRICE_PER_DURABILITY_POINT) {
            Material material = Material.matchMaterial(selector);
            if (material == null) {
                return false;
            }
            String currentValue;
            if (setting == GlobalSetting.BASE_PRICE) {
                currentValue = String.valueOf(settings.getBasePrice(material));
            } else {
                currentValue = String.valueOf(settings.getPricePerDurabilityPoint(material));
            }
            displaySuccessMessage(sender, Message.getItemCurrentValueMessage(setting.getCommandName(), ItemType.MATERIAL,
                    material.name(), currentValue));
            return true;
        } else if (setting == GlobalSetting.ENCHANTMENT_COST) {
            Enchantment enchantment = Enchantment.getByKey(NamespacedKey.minecraft(selector));
            if (enchantment == null) {
                return false;
            }
            displaySuccessMessage(sender, Message.getItemCurrentValueMessage(setting.getCommandName(), ItemType.ENCHANTMENT,
                    enchantment.toString(), String.valueOf(settings.getEnchantmentCost(enchantment))));
            return true;
        } else {
            return false;
        }
    }

    /**
     * Gets whether a command name matches a special case command
     *
     * @param commandName <p>The command specified</p>
     * @return <p>True if the command is a special case</p>
     */
    private boolean isSpecialCase(String commandName) {
        return commandName.equalsIgnoreCase(GlobalSetting.BASE_PRICE.getCommandName()) ||
                commandName.equalsIgnoreCase(GlobalSetting.PRICE_PER_DURABILITY_POINT.getCommandName()) ||
                commandName.equalsIgnoreCase(GlobalSetting.ENCHANTMENT_COST.getCommandName());
    }

    /**
     * Updates a special-case configuration value if a special-case is encountered
     *
     * @param settings              <p>The settings to modify</p>
     * @param detectedGlobalSetting <p>The global setting specified</p>
     * @param args                  <p>All arguments given</p>
     * @param sender                <p>The command sender to notify if successful</p>
     * @return <p>True if already handled as a special case</p>
     */
    private boolean updateSpecialCase(GlobalSettings settings, GlobalSetting detectedGlobalSetting, String[] args,
                                      CommandSender sender) {
        if (!TypeValidationHelper.isValid(SettingValueType.POSITIVE_DOUBLE, args[2], sender)) {
            return true;
        }
        double newPrice = Double.parseDouble(args[2]);
        String itemChanged;
        ItemType itemType;
        String newValue = String.valueOf(newPrice);

        if (detectedGlobalSetting == GlobalSetting.BASE_PRICE ||
                detectedGlobalSetting == GlobalSetting.PRICE_PER_DURABILITY_POINT) {
            Material material = InputParsingHelper.matchMaterial(args[1]);
            if (material == null) {
                return false;
            }
            itemType = ItemType.MATERIAL;
            itemChanged = material.name();
            if (detectedGlobalSetting == GlobalSetting.BASE_PRICE) {
                settings.setBasePrice(material, newPrice);
            } else {
                settings.setPricePerDurabilityPoint(material, newPrice);
            }
        } else if (detectedGlobalSetting == GlobalSetting.ENCHANTMENT_COST) {
            Enchantment enchantment = InputParsingHelper.matchEnchantment(args[1]);
            if (enchantment == null) {
                return false;
            }
            itemType = ItemType.ENCHANTMENT;
            itemChanged = enchantment.toString();
            settings.setEnchantmentCost(enchantment, newPrice);
        } else {
            return false;
        }

        displaySuccessMessage(sender, Message.getItemValueChangedMessage(detectedGlobalSetting.getCommandName(),
                itemType, itemChanged, newValue));
        return true;
    }

}
