/*
 *   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.lobby.portal;

import de.steamwar.lobby.LobbySystem;
import de.steamwar.lobby.command.ModifyCommand;
import de.steamwar.lobby.listener.Portals;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.util.Vector;

import java.util.*;
import java.util.logging.Level;

public class TeleportPortal implements PortalHandler {

    private static final List<TeleportPortal> portals = new ArrayList<>();

    private final Portal portal;
    private final String target;

    private final Set<TeleportPortal> sources = new HashSet<>();

    public TeleportPortal(Map<String, Object> section, Portal portal) {
        this.portal = portal;
        this.target = (String) section.get("target");
        init();
    }

    public TeleportPortal(Portal portal, String target) {
        this.portal = portal;
        this.target = target;
        init();
    }

    private void init() {
        portals.stream().filter(p -> p.target.equals(portal.getId())).forEach(sources::add);
        portals.stream().filter(p -> p.portal.getId().equals(target)).forEach(p -> p.sources.add(this));
        portals.add(this);
    }

    @Override
    public void handle(Player player, Location from, Location to) {
        Deque<Portal> stack = Portals.getStack(player);
        if(!stack.isEmpty() && sources.contains(stack.peek().getHandler())) {
            teleport(player, from, to, stack.pop());
        } else {
            teleport(player, from, to, Portal.getPortal(target));
        }
    }

    private void teleport(Player player, Location from, Location to, Portal target) {
        if(target == null) {
            LobbySystem.getInstance().getLogger().log(Level.WARNING, "Portal with unknown target: " + portal.getId());
            player.sendMessage("§cAus unbekannten Gründen führt dieses Portal zurzeit in den Limbus");
            return;
        }
        if(ModifyCommand.modifying(player))
            player.sendMessage("teleport " + portal.getId() + " -> " + target.getId());

        Vector normalized = portal.normalize(to);
        if (target.getDepth() != 0.0) {
            normalized.setX(1 - portal.normalize(from).getX());
        }
        Location portalTo = target.denormalize(normalized).toLocation(to.getWorld(), (float) (to.getYaw() - Math.toDegrees(target.getYrotation() - portal.getYrotation())), to.getPitch());
        player.teleport(portalTo, PlayerTeleportEvent.TeleportCause.PLUGIN);
        player.playSound(portalTo, Sound.BLOCK_ENCHANTMENT_TABLE_USE, 0.25f, 1.0f);
    }

    @Override
    public void serialize(Map<String, Object> map) {
        map.put("target", target);
    }

    @Override
    public PortalType type() {
        return PortalType.TELEPORT;
    }

    @Override
    public void delete() {
        portals.remove(this);
        portals.forEach(p -> p.sources.remove(this));
    }

    @Override
    public String toString() {
        return "Teleport: " + target;
    }
}
