/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.schematicsystem.commands.schematiccommand;

import de.steamwar.command.TypeMapper;
import de.steamwar.schematicsystem.SchematicSystem;
import de.steamwar.sql.*;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.getUser;

public class SchematicMapper {

    private static final TypeMapper<SchematicNode> publicCommandTypeMapper = publicNodeTypeMapper();

    public static TypeMapper<SchematicNode> publicNodeTypeMapper() {
        return new TypeMapper<SchematicNode>() {
            @Override
            public List<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
                return SchematicNode.getNodeTabcomplete(SteamwarUser.byId(0), s);
            }

            @Override
            public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
                return SchematicNode.getNodeFromPath(SteamwarUser.byId(0), s);
            }
        };
    }

    public static TypeMapper<NodeMember> nodeMemberTypeMapper() {
        return new TypeMapper<NodeMember>() {
            @Override
            public NodeMember map(CommandSender commandSender, String[] previousArguments, String s) {
                SchematicNode node = SchematicNode.getNodeFromPath(getUser((Player) commandSender), previousArguments[previousArguments.length - 1]);
                SteamwarUser user = SteamwarUser.get(s);
                return NodeMember.getNodeMember(node.getId(), user.getId());
            }

            @Override
            public List<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
                return Optional.ofNullable(SchematicNode.getNodeFromPath(getUser((Player) commandSender), strings[strings.length - 1]))
                        .map(SchematicNode::getMembers)
                        .map(nodeMembers -> nodeMembers.stream().map(NodeMember::getMember).map(SteamwarUser::byId).map(SteamwarUser::getUserName).collect(Collectors.toList()))
                        .orElse(Collections.emptyList());
            }
        };
    }

    public static TypeMapper<SchematicNode> dirNodeTypeMapper() {
        return new TypeMapper<SchematicNode>() {
            @Override
            public List<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
                List<String> list = SchematicNode.getNodeTabcomplete(getUser((Player) commandSender), s);
                list.removeIf(s1 -> !s1.endsWith("/"));
                return list;
            }

            @Override
            public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
                SchematicNode node = SchematicNode.getNodeFromPath(getUser((Player) commandSender), s);
                if (node.isDir()) {
                    return node;
                } else {
                    return null;
                }
            }
        };
    }

    public static TypeMapper<SchematicNode> publicDirNodeTypeMapper() {
        return new TypeMapper<SchematicNode>() {
            @Override
            public Collection<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
                Collection<String> list = publicCommandTypeMapper.tabCompletes(commandSender, strings, s);
                list.removeIf(s1 -> !s1.endsWith("/"));
                return list;
            }

            @Override
            public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
                SchematicNode node = publicCommandTypeMapper.map(commandSender, previousArguments, s);
                if (node.isDir()) {
                    return node;
                } else {
                    return null;
                }
            }
        };
    }

    public static TypeMapper<String> stringTabMapper() {
        return new TypeMapper<String>() {
            @Override
            public List<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
                List<String> list = SchematicNode.getNodeTabcomplete(getUser((Player) commandSender), s);
                list.removeIf(s1 -> !s1.endsWith("/"));
                return list;
            }

            @Override
            public String map(CommandSender commandSender, String[] previousArguments, String s) {
                return s;
            }
        };
    }

    public static TypeMapper<String> stringMapper() {
        return new TypeMapper<String>() {
            @Override
            public List<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
                List<String> list = SchematicNode.getNodeTabcomplete(getUser((Player) commandSender), s);
                list.add(s);
                return list;
            }

            @Override
            public String map(CommandSender commandSender, String[] previousArguments, String s) {
                return s;
            }
        };
    }

    public static TypeMapper<SchematicType> typeTypeMapper() {
        return new TypeMapper<SchematicType>() {
            @Override
            public List<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
                return SchematicType.values().stream().filter(SchematicType::isAssignable).map(SchematicType::name).collect(Collectors.toList());
            }

            @Override
            public SchematicType map(CommandSender commandSender, String[] previousArguments, String s) {
                return SchematicType.values().stream().filter(type -> type.name().equals(s)).collect(Collectors.toList()).get(0);
            }
        };
    }

    public static TypeMapper<SchematicNode> nodeTypeMapper() {
        return new TypeMapper<SchematicNode>() {
            @Override
            public List<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
                return SchematicNode.getNodeTabcomplete(getUser((Player) commandSender), s);
            }

            @Override
            public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
                return SchematicNode.getNodeFromPath(getUser((Player) commandSender), s);
            }
        };
    }

    public static TypeMapper<GameModeConfig<Material, String>> gameModeConfigTypeMapper() {
        return new TypeMapper<GameModeConfig<Material, String>>() {
            @Override
            public Collection<String> tabCompletes(CommandSender commandSender, String[] strings, String s) {
                return SchematicType.values().stream().filter(type -> SchematicSystem.getGameModeConfig(type) != null).map(SchematicType::name).collect(Collectors.toList());
            }

            @Override
            public GameModeConfig<Material, String> map(CommandSender commandSender, String[] previousArguments, String s) {
                return SchematicType.values().stream().filter(type -> type.name().equalsIgnoreCase(s)).map(SchematicSystem::getGameModeConfig).findAny().orElse(null);
            }
        };
    }
}
