package com.rs.game.map.bossInstance;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import com.rs.Settings;
import com.rs.game.World;
import com.rs.game.WorldTile;
//import com.rs.game.map.bossInstance.impl.AraxxiInstance;
import com.rs.game.map.bossInstance.impl.CorporealBeastInstance;
import com.rs.game.map.bossInstance.impl.DagannothKingsInstance;
import com.rs.game.map.bossInstance.impl.ExiledKalphiteQueenInstance;
import com.rs.game.map.bossInstance.impl.KalphiteKingInstance;
import com.rs.game.map.bossInstance.impl.KalphiteQueenInstance;
import com.rs.game.map.bossInstance.impl.KingBlackDragonInstance;
import com.rs.game.map.bossInstance.impl.VoragoInstance;
import com.rs.game.player.Player;
import com.rs.utils.Logger;
import com.rs.utils.Utils;

public class BossInstanceHandler {

    // to make sure no issues
    public static final Object LOCK = new Object();

    public static enum Boss {
	King_Black_Dragon(KingBlackDragonInstance.class, 50000, 200, false, true, new WorldTile(3051, 3520, 0),
		new WorldTile(2273, 4681, 0), null, "BossInstanceController", 14),

	//Araxxi(AraxxiInstance.class, 0, 50, false, false, new WorldTile(4486, 6266, 1), new WorldTile(4490, 6266, 1),
	//	new WorldTile(3542, 3310, 0), "AraxxiInstanceController", 1155),

	Kalphite_Queen(KalphiteQueenInstance.class, 100000, 200, false, true, new WorldTile(3446, 9496, 0),
		new WorldTile(3508, 9494, 0), null, "KalphiteQueenInstanceController", 212),

	Exiled_Kalphite_Queen(ExiledKalphiteQueenInstance.class, 100000, 200, false, true, new WorldTile(2995, 1617, 0),
		new WorldTile(2967, 1711, 0), null, "KalphiteQueenInstanceController", 212),

	Dagannoth_Kings(DagannothKingsInstance.class, 150000, 200, false, true, new WorldTile(1912, 4367, 0),
		new WorldTile(2900, 4449, 0), null, "DagannothKingsInstanceController", 365),

	Corporeal_Beast(CorporealBeastInstance.class, 300000, 200, false, true, new WorldTile(2970, 4384, 2),
		new WorldTile(2974, 4384, 2), null, "CorporealBeastInstanceController", 617),

	Kalphite_King(KalphiteKingInstance.class, 0, 200, false, false, new WorldTile(2971, 1656, 0),
		new WorldTile(2974, 1746, 0), null, "KalphiteKingInstanceController", 1140),

	Vorago(VoragoInstance.class, 1000000, 50, true, true, new WorldTile(2972, 3431, 0),
		new WorldTile(3043, 6100, 0), new WorldTile(3072, 6176, 0), "VoragoInstanceController", 1155)

	;
	private final Map<String, BossInstance> cachedInstances = Collections
		.synchronizedMap(new HashMap<String, BossInstance>());
	private Class<? extends BossInstance> instance;
	private int initialCost, maxPlayers, musicId;
	private boolean hasHM, publicVersion;
	private WorldTile insideTile, outsideTile, graveStoneTile;
	private String controllerName;

	private Boss(Class<? extends BossInstance> instance, int initialCost, int maxPlayers, boolean hasHM,
		boolean publicVersion, WorldTile outsideTile, WorldTile insideTile, WorldTile graveStoneTile,
		String controllerName, int musicId) {
	    this.instance = instance;
	    this.initialCost = initialCost;
	    this.maxPlayers = maxPlayers;
	    this.hasHM = hasHM;
	    this.publicVersion = publicVersion;
	    this.insideTile = insideTile;
	    this.outsideTile = outsideTile;
	    this.graveStoneTile = graveStoneTile;
	    this.controllerName = controllerName;
	    this.musicId = musicId;
	}

	public Map<String, BossInstance> getCachedInstances() {
	    return cachedInstances;
	}

	public String getControllerName() {
	    return controllerName;
	}

	public WorldTile getInsideTile() {
	    return insideTile;
	}

	public WorldTile getOutsideTile() {
	    return outsideTile;
	}

	public WorldTile getGraveStoneTile() {
	    return graveStoneTile;
	}

	public boolean isHasHM() {
	    return hasHM;
	}

	public int getMaxPlayers() {
	    return maxPlayers;
	}

	public int getInitialCost() {
	    return initialCost;
	}

	public int getMusicId() {
	    return musicId;
	}

	public boolean hasPublicVersion() {
	    return publicVersion;
	}

    }

    public static void enterInstance(Player player, Boss boss) {
	player.getDialogueManager().startDialogue("BossInstanceD", boss);
    }

    private static void createInstance(Player player, Boss boss, int maxPlayers, int minCombat, int spawnSpeed,
	    int protection, boolean practiseMode, boolean hardMode) {
	createInstance(player,
		new InstanceSettings(boss, maxPlayers, minCombat, spawnSpeed, protection, practiseMode, hardMode));
    }

    public static void createInstance(Player player, InstanceSettings settings) {
	synchronized (LOCK) {

	    try {
		String key = player == null ? "" : player.getUsername();
		BossInstance instance = findInstance(settings.getBoss(), key);
		if (instance == null) {
		    if (player == null && !settings.getBoss().publicVersion) {
			if (Settings.DEBUG)
			    Logger.log(BossInstanceHandler.class, "Not a public instance. Can't create it.");
			return;
		    }
		    instance = settings.getBoss().instance.getDeclaredConstructor(Player.class, InstanceSettings.class)
			    .newInstance(player, settings);
		    settings.getBoss().cachedInstances.put(key, instance);
		} else {// recreating the instance but not gonna replace
		    // settings since already exists(instead, increase time)
		    settings.setCreationTime(Utils.currentTimeMillis());
		    joinInstance(player, settings.getBoss(), key, false); // enter
		}
	    } catch (Throwable e) {
		Logger.handle(e);
	    }

	}
    }

    /*
     * login means reloging in a public instance(u cant login into private, but
     * lets keep this in case rs lets u in future)
     */
    public static BossInstance joinInstance(Player player, Boss boss, String key, boolean login) {
	synchronized (LOCK) {

	    BossInstance instance = findInstance(boss, key);
	    if (instance == null) { // not username
		Player owner = World.getPlayerByDisplayName(key);
		if (owner != null) {
		    key = owner.getUsername();
		    instance = findInstance(boss, key);
		}
	    }

	    if (instance == null) {
		if (key.equals("")) { // supposed to be public instance
		    player.getPackets().sendGameMessage("This boss has no public instance.");
		    return null;
		}
		player.getPackets().sendGameMessage("That player is offline, or has privacy mode enabled.");
		return null;
	    }
	    // loading
	    if (!instance.isInstanceReady())
		return null;
	    if (!key.equals("") && !player.getUsername().equals(key)) {
		if (instance.getSettings().getMinCombat() > player.getSkills().getCombatLevelWithSummoning()) {
		    player.getPackets().sendGameMessage("Your combat level is too low to enter this session.");
		    return null;
		}
		if (instance.getSettings().getProtection() == BossInstance.FRIENDS_ONLY) {
		    Player owner = World.getPlayer(key);
		    if (owner == null || !owner.getFriendsIgnores().isFriend(player.getDisplayName())) {
			player.getPackets().sendGameMessage("That player is offline, or has privacy mode enabled.");
			return null;
		    }
		}
		if (instance.getSettings().getMaxPlayers() - 1 <= instance.getPlayersCount()) {
		    player.getPackets().sendGameMessage("This instance is full.");
		    return null;
		}
	    }
	    instance.enterInstance(player, login);
	    return instance;
	}
    }

    public static BossInstance findInstance(Boss boss, String key) {
	synchronized (LOCK) {
	    return boss.cachedInstances.get(key);
	}
    }

    public static final void init() {
	for (Boss boss : Boss.values()) {
	    if (!boss.publicVersion)
		continue;
	    try {
		createInstance(null, boss, boss.maxPlayers, 1, BossInstance.STANDARD, BossInstance.FFA, false, false);
	    } catch (Throwable e) {
		Logger.handle(e);
	    }
	}
    }

}
