package tc.oc.lobby.bukkit.gizmos.chicken;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.Maps;
import com.google.inject.Injector;
import net.md_5.bungee.api.chat.TranslatableComponent;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import tc.oc.api.bukkit.users.Users;
import tc.oc.commons.bukkit.nick.IdentityProvider;
import tc.oc.commons.bukkit.util.NMSHacks;
import tc.oc.commons.core.chat.Component;
import tc.oc.lobby.bukkit.Lobby;
import tc.oc.lobby.bukkit.LobbyTranslations;
import tc.oc.lobby.bukkit.gizmos.Gizmo;
import tc.oc.lobby.bukkit.gizmos.GizmoConfig;
import tc.oc.lobby.bukkit.gizmos.Gizmos;
import tc.oc.commons.bukkit.raindrops.RaindropUtil;

public class ChickenGizmo extends Gizmo implements Listener {

    private class Chicken implements Listener {
        final Player player;
        final NMSHacks.FakeChicken entity;
        final Set<Player> viewers = new HashSet<>();

        Chicken(Player player) {
            this.player = player;
            this.entity = new NMSHacks.FakeChicken(
                player.getWorld(),
                identityProvider.currentIdentity(player).getPublicName()
            );

            eventRegistry.registerListener(this);
        }

        boolean add(Player viewer) {
            if(viewers.add(viewer)) {
                viewer.hidePlayer(player);
                entity.spawn(viewer, player.getLocation());
                viewer.playSound(viewer.getLocation(), Sound.ENTITY_CHICKEN_AMBIENT, 1f, 1f);
                viewer.playSound(viewer.getLocation(), Sound.ENTITY_CHICKEN_HURT, 1f, 1f);
                return true;
            }

            return false;
        }

        @EventHandler
        void quit(PlayerQuitEvent event) {
            viewers.remove(event.getPlayer());
        }

        void move(PlayerMoveEvent event) {
            for(Player viewer : viewers) {
                entity.teleport(viewer, event.getTo());
            }
        }

        void destroy() {
            eventRegistry.unregisterListener(this);
            for(Player viewer : viewers) {
                entity.destroy(viewer);
            }
        }
    }

    private final Map<Player, Chicken> chickens = new HashMap<>();
    private final IdentityProvider identityProvider;
    private final EventRegistry eventRegistry;

    public Map<Player, Integer> chickendCount = Maps.newHashMap();

    public ChickenGizmo(String name, String prefix, String description, Material icon, int cost) {
        super(name, prefix, description, icon, cost);

        final Injector injector = Lobby.get().injector();
        identityProvider = injector.getInstance(IdentityProvider.class);
        eventRegistry = injector.getInstance(EventRegistry.class);
    }

    @Override
    public String getName(Player viewer) {
        return LobbyTranslations.get().t("gizmo.chicken.name", viewer);
    }

    @Override
    public String getDescription(Player viewer) {
        return LobbyTranslations.get().t("gizmo.chicken.description", viewer);
    }

    @Override
    protected void initialize() {
        Bukkit.getPluginManager().registerEvents(this, Lobby.get());
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    void playerMove(PlayerMoveEvent event) {
        final Chicken chicken = chickens.get(event.getPlayer());
        if(chicken != null) chicken.move(event);
    }

    @EventHandler
    public void playerQuit(final PlayerQuitEvent event) {
        chickendCount.remove(event.getPlayer());
        final Chicken chicken = chickens.remove(event.getPlayer());
        if(chicken != null) chicken.destroy();
    }

    @EventHandler
    public void entityDamage(final EntityDamageEvent event) {
        if(!(event instanceof EntityDamageByEntityEvent)) return;
        EntityDamageByEntityEvent realEvent = (EntityDamageByEntityEvent) event;
        if(!(realEvent.getDamager() instanceof Player) || !(realEvent.getEntity() instanceof Player)) return;

        final Player damager = (Player) realEvent.getDamager();
        final Player victim = (Player) realEvent.getEntity();

        if(victim.hasPermission(GizmoConfig.EXEMPT_PERMISSION)) return;

        if(!(Gizmos.gizmoMap.get(damager) instanceof ChickenGizmo)) return;
        if(damager.getItemInHand().getType() != this.getIcon()) return;

        final Chicken chicken = chickens.computeIfAbsent(victim, Chicken::new);
        if(!chicken.add(damager)) return;

        chickendCount.compute(victim, (player, count) -> {
            count = count == null ? 0 : count + 1;
            if(count > 0 && count % 10 == 0) {
                RaindropUtil.giveRaindrops(
                    Users.playerId(damager), 1, null,
                    new TranslatableComponent("gizmo.chicken.raindropsResult", new Component(String.valueOf(count), net.md_5.bungee.api.ChatColor.GOLD))
                );
            }
            return count;
        });

        event.setCancelled(true);
    }
}
