package fi.flexplex.lib;

import java.io.IOException;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

public final class PlayerFriends {

	private final GraphQLApi graphQLApi;
	private final String token;
	private final String player;
	private final Set<UUID> friends = new HashSet<>();
	private final Set<UUID> incomingFriendRequests = new HashSet<>();
	private final Set<UUID> outcomingFriendRequests = new HashSet<>();
	private boolean friendRequestsEnabled;
	private long lastUsed = System.currentTimeMillis();

	protected PlayerFriends(final GraphQLApi graphQLApi, final String token, final String player) throws IOException {
		this.graphQLApi = graphQLApi;
		this.token = token;
		this.player = player;
		if (!this.update()) {
			throw new IOException();
		}
	}

	protected long getLastUsed() {
		return this.lastUsed;
	}

	protected boolean update() {
		final Optional<JsonObject> result = this.graphQLApi.execute(
			"query{" +
				"player(uuid:\"" + this.player + "\"){" +
					"acceptFriendRequests," +
					"friends{uuid}," +
					"incomingFriendRequests(token:\"" + this.token + "\"){uuid}," +
					"outcomingFriendRequests(token:\"" + this.token + "\"){uuid}" +
				"}" +
			"}"
		);
		if (result.isEmpty()) {
			return false;
		}

		final JsonObject playerObject = result.get().get("player").getAsJsonObject();

		this.friendRequestsEnabled = playerObject.get("acceptFriendRequests").getAsBoolean();

		this.friends.clear();
		for (final JsonElement element : playerObject.get("friends").getAsJsonArray()) {
			this.friends.add(UUID.fromString(element.getAsJsonObject().get("uuid").getAsString()));
		}

		this.incomingFriendRequests.clear();
		for (final JsonElement element : playerObject.get("incomingFriendRequests").getAsJsonArray()) {
			this.incomingFriendRequests.add(UUID.fromString(element.getAsJsonObject().get("uuid").getAsString()));
		}

		this.outcomingFriendRequests.clear();
		for (final JsonElement element : playerObject.get("outcomingFriendRequests").getAsJsonArray()) {
			this.outcomingFriendRequests.add(UUID.fromString(element.getAsJsonObject().get("uuid").getAsString()));
		}

		return true;
	}

	/**
	 * Get friends
	 * @return friends
	 */
	public Set<UUID> getFriends() {
		this.lastUsed = System.currentTimeMillis();
		return this.friends;
	}

	/**
	 * Get incoming friend requests
	 * @return friend requests
	 */
	public Set<UUID> getIncomingFriendRequests() {
		this.lastUsed = System.currentTimeMillis();
		return this.incomingFriendRequests;
	}

	/**
	 * Get outcoming friend requests
	 * @return friend requests
	 */
	public Set<UUID> getOutcomingFriendRequests() {
		this.lastUsed = System.currentTimeMillis();
		return this.outcomingFriendRequests;
	}

	/**
	 * Check if friend requests is enabled
	 * @return is friend requests enabled
	 */
	public boolean isFriendRequestsEnabled() {
		this.lastUsed = System.currentTimeMillis();
		return friendRequestsEnabled;
	}

	/**
	 * Create new friend request
	 * @param player from
	 * @param targetPlayer to
	 * @return true if was created successfully
	 */
	public boolean createFriendRequest(final String player, final String targetPlayer) {
		this.lastUsed = System.currentTimeMillis();
		final Optional<JsonObject> result = this.graphQLApi.execute(
			"mutation{" +
				"createFriendRequest(" +
					"token:\"" + this.token + "\"," +
					"player:\"" + player + "\"," +
					"targetPlayer:\"" + targetPlayer + "\"" +
				")" +
			"}"
		);
		return result.isPresent() && result.get().get("createFriendRequest").getAsBoolean();
	}

	/**
	 * Accept incoming friend request
	 * @param player coming from
	 * @param targetPlayer who is accepting
	 * @return true if was accepted successfully
	 */
	public boolean acceptFriendRequest(final String player, final String targetPlayer) {
		this.lastUsed = System.currentTimeMillis();
		final Optional<JsonObject> result = this.graphQLApi.execute(
			"mutation{" +
				"acceptFriendRequest(" +
					"token:\"" + this.token + "\"," +
					"player:\"" + player + "\"," +
					"targetPlayer:\"" + targetPlayer + "\"" +
				")" +
			"}"
		);
		return result.isPresent() && result.get().get("acceptFriendRequest").getAsBoolean();
	}

	/**
	 * Delete friend or friend request
	 * @param player
	 * @param targetPlayer
	 * @return true if was deleted successfully
	 */
	public boolean deleteFriend(final String player, final String targetPlayer) {
		this.lastUsed = System.currentTimeMillis();
		final Optional<JsonObject> result = this.graphQLApi.execute(
			"mutation{" +
				"deleteFriend(" +
					"token:\"" + this.token + "\"," +
					"player:\"" + player + "\"," +
					"targetPlayer:\"" + targetPlayer + "\"" +
				")" +
			"}"
		);
		return result.isPresent() && result.get().get("deleteFriend").getAsBoolean();
	}

	/**
	 * Change settings does player accept incoming friend requests
	 * @param player
	 * @param enabled
	 * @return true if was changed successfully
	 */
	public boolean setFriendRequestsEnabled(final String player, final boolean enabled) {
		this.lastUsed = System.currentTimeMillis();
		final Optional<JsonObject> result = this.graphQLApi.execute(
			"mutation{" +
				"updateAcceptFriendRequests(" +
					"token:\"" + this.token + "\"," +
					"player:\"" + player + "\"," +
					"acceptRequests:" + (enabled ? "true" : "false") +
				")" +
			"}"
		);
		return result.isPresent() && result.get().get("updateAcceptFriendRequests").getAsBoolean();
	}

}