package de.hessj.environmentex;

import org.bukkit.GameRule;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Item;
import org.bukkit.entity.ItemFrame;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.Event.Result;
import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.hanging.HangingBreakEvent;
import org.bukkit.event.hanging.HangingPlaceEvent;
import org.bukkit.event.inventory.PrepareItemCraftEvent;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.scheduler.BukkitRunnable;

public class InvisibleFrame implements Listener {
   Location aboutToPlaceLocation = null;
   BlockFace aboutToPlaceFace = null;
   long hangingBrokenAtTick = -1L;
   static boolean wasInvisible = false;
   static NamespacedKey nsk = new NamespacedKey(App.main, "invisible");

   @EventHandler
   public void onHangingPlace(HangingPlaceEvent event) {
      EntityType entityType = event.getEntity().getType();
      if (entityType == EntityType.ITEM_FRAME || entityType == EntityType.GLOW_ITEM_FRAME) {
         Location location = event.getBlock().getLocation();
         BlockFace face = event.getBlockFace();
         if (location.equals(this.aboutToPlaceLocation) && face == this.aboutToPlaceFace) {
            this.aboutToPlaceLocation = null;
            this.aboutToPlaceFace = null;
            event.getEntity().getPersistentDataContainer().set(nsk, PersistentDataType.BYTE, (byte) 1);
         }

      }
   }

   @EventHandler
   public void onHangingBreak(HangingBreakByEntityEvent event) {
      this.hangingBrokenAtTick = event.getEntity().getWorld().getFullTime();
      if (event.getEntity().getPersistentDataContainer().has(nsk,
            PersistentDataType.BYTE)) {
         wasInvisible = true;
      } else {
         wasInvisible = false;
      }
   }

   @EventHandler
   public void onItemSpawn(ItemSpawnEvent event) {
      Item entity = event.getEntity();
      ItemStack stack = entity.getItemStack();
      long now = entity.getWorld().getFullTime();
      if (now == this.hangingBrokenAtTick && wasInvisible) {
         if (stack.getType() == Material.ITEM_FRAME) {
            stack.setItemMeta(App.main.meta);
         } else {
            if (stack.getType() != Material.GLOW_ITEM_FRAME) {
               return;
            }

            stack.setItemMeta(App.main.meta2);
         }

         this.hangingBrokenAtTick = -1L;
         entity.setItemStack(stack);
      }
   }

   @EventHandler
   public void onPlayerInteract(PlayerInteractEvent event) {
      ItemStack item = event.getItem();
      if (isInvisibleItemFrame(item) && event.useItemInHand() != Result.DENY) {
         Block block = event.getClickedBlock();
         if (block != null) {
            this.aboutToPlaceLocation = block.getLocation();
            this.aboutToPlaceFace = event.getBlockFace();
         }

      }
   }

   @EventHandler
   public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
      Entity entity = event.getRightClicked();
      if (isInvisibleItemFrame(entity)) {
         ItemFrame frame = (ItemFrame) entity;
         (new ItemFrameUpdateRunnable(frame)).runTask(App.main);

      }

   }

   @EventHandler
   public void onPrepareItemCraft(PrepareItemCraftEvent event) {
      if (isInvisibleItemFrame(event.getInventory().getResult())) {
         HumanEntity entity = event.getView().getPlayer();
         Boolean limitedCrafting = (Boolean) entity.getWorld().getGameRuleValue(GameRule.DO_LIMITED_CRAFTING);
         boolean entityHasRecipe = entity.hasDiscoveredRecipe(new NamespacedKey(App.main, "invisible_item_frame"));
         if (Boolean.TRUE.equals(limitedCrafting) && !entityHasRecipe) {
            event.getInventory().setResult(new ItemStack(Material.AIR));
         }
      }
   }

   @EventHandler
   public void onBreakBlockBehindFrame(HangingBreakEvent e) {
      this.hangingBrokenAtTick = e.getEntity().getWorld().getFullTime();
      Entity entity = e.getEntity();
      if (isInvisibleItemFrame(entity)) {
         ItemFrame frame = (ItemFrame) entity;
         (new ItemFrameUpdateRunnable(frame)).runTask(App.main);
         wasInvisible = true;
      } else {
         wasInvisible = false;
      }

   }

   public static boolean isInvisibleItemFrame(ItemStack item) {
      if (item == null) {
         return false;
      } else {
         ItemMeta meta = item.getItemMeta();
         return meta == null ? false
               : meta.getPersistentDataContainer().has(nsk,
                     PersistentDataType.BYTE);
      }
   }

   public static boolean isInvisibleItemFrame(Entity entity) {
      if (entity == null) {
         return false;
      } else {
         EntityType type = entity.getType();

         if (type != EntityType.ITEM_FRAME && type != EntityType.GLOW_ITEM_FRAME) {
            return false;
         }
         if (entity.getPersistentDataContainer().has(nsk,
               PersistentDataType.BYTE)) {
            wasInvisible = true;
            return true;
         }
         return false;
      }
   }
}

class ItemFrameUpdateRunnable extends BukkitRunnable {
   ItemFrame itemFrame;

   ItemFrameUpdateRunnable(ItemFrame itemFrame) {
      this.itemFrame = itemFrame;
   }

   public void run() {
      ItemStack item = this.itemFrame.getItem();
      boolean hasItem = item.getType() != Material.AIR;
      this.itemFrame.setVisible(!hasItem);
   }
}