package com.rs.game.player.content.surpriseevents;

import java.util.ArrayList;
import java.util.List;
import java.util.TimerTask;

import com.rs.Settings;
import com.rs.executor.GameExecutorManager;
import com.rs.game.World;
import com.rs.game.player.Player;
import com.rs.game.tasks.WorldTask;
import com.rs.game.tasks.WorldTasksManager;
import com.rs.utils.Logger;
import com.rs.utils.Utils;

public class LastManStanding implements SurpriseEvent {

	/**
	 * 3 minutes before the event starts.
	 */
	public static final int PREP_MINS = 5;
	/**
	 * Maximum game time.
	 */
	public static final int GAME_MINS = 15;

	/**
	 * Cash for event winner.
	 */
	public static final int REWARD_CASH_FINAL = 5000000;
	/**
	 * Spins for event winner.
	 */
	public static final int REWARD_SPINS_FINAL = 10;

	/**
	 * Drop rate modifier.
	 */
	public static final double REWARD_DROP_MOD_PER_KILL = 0.75;
	/**
	 * Cash reward for single kill.
	 */
	public static final int REWARD_CASH_PER_KILL = 300000;

	/**
	 * Phases... 0 - Pre-start 1 - Initializing area 2 - Accepting players/waiting till game 3 - Game 4 - Shutdown
	 */
	private int phase = 0;

	/**
	 * Our arena.
	 */
	public EventArena arena;
	/**
	 * Our task.
	 */
	private TimerTask task;

	/**
	 * When we will start game and end game.
	 */
	private long startTime, endTime;

	/**
	 * Our lock
	 */
	private Object lock = new Object();

	/**
	 * List of all players.
	 */
	private List<Player> players = new ArrayList<Player>();

	/**
	 * Alive players.
	 */
	private List<Player> alive = new ArrayList<Player>();

	public void start() {
		if (phase != 0)
			return;
		phase = 1;
		GameExecutorManager.fastExecutor.schedule(task = new TimerTask() {
			@Override
			public void run() {
				try {
					if (phase == 2 || phase == 3)
						LastManStanding.this.run();
					else if (phase == 4) {
						task.cancel();
						task = null;

						GameExecutorManager.slowExecutor.execute(new Runnable() {
							@Override
							public void run() {
								arena.destroy();
								arena = null;
							}
						});
					}
				} catch (Throwable e) {
					Logger.handle(e);
				}
			}
		}, 0L, 1000);

		GameExecutorManager.slowExecutor.execute(new Runnable() {
			@Override
			public void run() {
				arena = ArenaFactory.randomEventArena(true);
				arena.create();
				phase = 2;
				timerinit();
			}
		});
	}

	private void timerinit() {
		startTime = Utils.currentTimeMillis() + (1000 * 60 * PREP_MINS);
		endTime = startTime + (1000 * 60 * GAME_MINS);
		World.sendNews(null, "Last man standing event will start in " + PREP_MINS + " minute! Talk to oracle to get there.", World.WORLD_NEWS);
	}

	private void run() {
		if (phase == 2 && canBegin())
			begin();
		else if (phase == 3 && canEnd())
			end();
	}

	private boolean canBegin() {
		synchronized (lock) {
			if (players.size() < 2)
				return false;
		}
		return Utils.currentTimeMillis() >= startTime;
	}

	private void begin() {
		phase = 3;
		synchronized (lock) {
			for (Player player : players) {
				player.setCanPvp(true);
				alive.add(player);
			}
		}
		World.sendNews(null, "Last man standing event has started!", World.WORLD_NEWS);
	}

	private boolean canEnd() {
		synchronized (lock) {
			return Utils.currentTimeMillis() >= endTime || players.size() < 1 || alive.size() < 2;
		}
	}

	private void end() {
		phase = 4;

		synchronized (lock) {
			if (alive.size() == 1) {
				Player winner = alive.iterator().next();
				World.sendNews(null, "Last man standing event has ended, winner: " + winner.getDisplayName(), World.WORLD_NEWS);

				winner.getSquealOfFortune().giveEarnedSpins(REWARD_SPINS_FINAL);
				winner.getInventory().addItemDrop(995, REWARD_CASH_FINAL);
			} else {
				World.sendNews(null, "Last man standing event has ended without winner.", World.WORLD_NEWS);
			}

			List<Player> ps = new ArrayList<Player>(players);
			for (Player player : ps)
				player.getControlerManager().forceStop();
		}

	}

	public void forceleave(final Player player) {
		synchronized (lock) {
			player.setCanPvp(false);
			player.stopAll();
			player.reset();
			player.getAppearence().setHidden(false);
			player.getAppearence().setIdentityHide(false);
			player.useStairs(-1, Settings.START_PLAYER_LOCATION, 0, 1);

			players.remove(player);
			alive.remove(player);
		}
	}

	@Override
	public void tryJoin(final Player player) {
		if (phase != 2)
			return;

		synchronized (lock) {
			players.add(player);
		}

		player.stopAll();
		player.reset();
		player.getAppearence().setHidden(false);
		player.getAppearence().setIdentityHide(true);
		player.useStairs(-1, arena.randomSpawn(), 0, 1);
		WorldTasksManager.schedule(new WorldTask() {
			@Override
			public void run() {
				if (player.getFamiliar() != null)
					player.getFamiliar().sendDeath(player);
				player.getControlerManager().startControler("LastManStandingController", LastManStanding.this);
			}
		}, 1);
	}

	public int getPhase() {
		return phase;
	}

	public long startTime() {
		return startTime;
	}

	public long endTime() {
		return endTime;
	}

	public Object getLock() {
		return lock;
	}

	public List<Player> getPlayers() {
		return players;
	}

	public List<Player> getAlive() {
		return alive;
	}

	public EventArena getArena() {
		return arena;
	}

}
