/*
 * This file is a part of the SteamWar software.
 *
 * Copyright (C) 2022  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.velocitycore.commands;

import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeValidator;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.persistent.Subserver;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.Tutorial;
import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.ServerStarter;
import de.steamwar.velocitycore.SubserverSystem;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.inventory.SWInventory;
import de.steamwar.velocitycore.inventory.SWItem;
import de.steamwar.velocitycore.inventory.SWListInv;
import de.steamwar.velocitycore.inventory.SWStreamInv;

import java.io.File;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

public class TutorialCommand extends SWCommand {

    public TutorialCommand() {
        super("tutorial");
    }

    @Register
    public void genericCommand(PlayerChatter sender) {
        openInventory(sender, true, false);
    }

    @Register("rate")
    public void rate(PlayerChatter sender) {
        sender.getPlayer().spoofChatInput("/tutorial rate");
    }

    @Register("rate")
    public void rate(PlayerChatter sender, int id) {
        Tutorial tutorial = Tutorial.get(id);
        if(tutorial == null) {
            sender.getPlayer().spoofChatInput("/tutorial rate");  // Catch players manually entering numbers
            return;
        }

        rate(sender, tutorial);
    }

    @Register(value = "create", description = "TUTORIAL_CREATE_HELP")
    public void create(PlayerChatter sender, String material, String... name) {
        create(sender, String.join(" ", name), material.toUpperCase());
    }

    @Register("own")
    public void own(PlayerChatter sender) {
        openInventory(sender, false, true);
    }

    @Register("unreleased")
    public void unreleased(@Validator("unreleased") PlayerChatter sender) {
        openInventory(sender, false, false);
    }

    @Validator("unreleased")
    public TypeValidator<Chatter> unreleasedChecker() {
        return (sender, value, messageSender) -> sender.user().hasPerm(UserPerm.TEAM);
    }

    private void openInventory(PlayerChatter sender, boolean released, boolean own) {
        SteamwarUser user = sender.user();

        new SWStreamInv<>(
                sender,
                new Message("TUTORIAL_TITLE"),
                (click, tutorial) -> {
                    if(!released && click.isShiftClick() && user.hasPerm(UserPerm.TEAM) && user.getId() != tutorial.getCreator()) {
                        tutorial.release();
                        openInventory(sender, released, own);
                        return;
                    } else if(own && click.isShiftClick() && click.isRightClick()) {
                        tutorial.delete();
                        SubserverSystem.deleteFolder(VelocityCore.local, world(tutorial).getPath());
                        openInventory(sender, released, own);
                        return;
                    }

                    new ServerStarter().tutorial(sender.getPlayer(), tutorial).start();
                },
                page -> (own ? Tutorial.getOwn(user.getId(), page, 45) : Tutorial.getPage(page, 45, released)).stream().map(tutorial -> new SWListInv.SWListEntry<>(getTutorialItem(tutorial, own), tutorial)).toList()
        ).open();
    }

    private SWItem getTutorialItem(Tutorial tutorial, boolean personalHighlights) {
        SWItem item = new SWItem(tutorial.getItem(), new Message("TUTORIAL_NAME", tutorial.getName()));
        item.setHideAttributes(true);

        item.addLore(new Message("TUTORIAL_BY", SteamwarUser.get(tutorial.getCreator()).getUserName()));
        item.addLore(new Message("TUTORIAL_STARS", String.format("%.1f", tutorial.getStars())));

        if (personalHighlights)
            item.addLore(new Message("TUTORIAL_DELETE"));

        if (personalHighlights && tutorial.isReleased())
            item.setEnchanted(true);

        return item;
    }

    private void rate(PlayerChatter sender, Tutorial tutorial) {
        int[] rates = new int[]{1, 2, 3, 4, 5};

        new SWListInv<>(sender, new Message("TUTORIAL_RATE_TITLE"), Arrays.stream(rates).mapToObj(rate -> new SWListInv.SWListEntry<>(new SWItem("NETHER_STAR", new Message("TUTORIAL_RATE", rate)), rate)).toList(), (click, rate) -> {
            tutorial.rate(sender.user().getId(), rate);
            SWInventory.close(sender);
        }).open();
    }

    private void create(PlayerChatter sender, String name, String item) {
        Subserver subserver = Subserver.getSubserver(sender.getPlayer());
        SteamwarUser user = sender.user();
        File tempWorld = new File(ServerStarter.TEMP_WORLD_PATH, ServerStarter.serverToWorldName(ServerStarter.bauServerName(user)));

        if(!Subserver.isBuild(subserver) || !subserver.isStarted() || !tempWorld.exists()) {
            sender.system("TUTORIAL_CREATE_MISSING");
            return;
        }

        subserver.execute("save-all");
        VelocityCore.schedule(() -> {
            Tutorial tutorial = Tutorial.create(user.getId(), name, item);
            File tutorialWorld = world(tutorial);

            if (tutorialWorld.exists())
                SubserverSystem.deleteFolder(VelocityCore.local, tutorialWorld.getPath());
            ServerStarter.copyWorld(VelocityCore.local, tempWorld.getPath(), tutorialWorld.getPath());
            sender.system("TUTORIAL_CREATED");
        }).delay(1, TimeUnit.SECONDS).schedule();
    }

    private File world(Tutorial tutorial) {
        return new File(ServerStarter.TUTORIAL_PATH, String.valueOf(tutorial.getTutorialId()));
    }
}
