package be.jeffcheasey88.peeratcode.model;

import java.util.Base64;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

public class Player implements Comparable<Player> {
	private String pseudo;
	private String email;
	private String firstname;
	private String lastname;
	private String description;
	private Set<Group> groups;
	private Set<Completion> completions = new HashSet<Completion>();
	private byte[] avatar;

	private int rank;

	private Set<Badge> badges;

	public Player(String pseudo, String email, String firstname, String lastname, String description) {
		this.pseudo = pseudo;
		this.email = email;
		this.firstname = firstname;
		this.lastname = lastname;
		this.description = description;
	}

	public Player(String pseudo, int score, int tries) {
		// For groups leaderboard
		this.pseudo = pseudo;
		this.completions.add(new Completion(tries, score));
		email = ""; // TO make compareTo and equals works as usual
	}

	public String getPseudo() {
		return this.pseudo;
	}

	public String getEmail() {
		return this.email;
	}

	public String getFirstname() {
		return this.firstname;
	}

	public String getLastname() {
		return this.lastname;
	}

	public String getDescription() {
		return this.description;
	}

	public Set<Group> getGroups() {
		return groups;
	}

	public JSONArray getJsonGroups() {
		if (groups != null) {
			JSONArray groupsJSON = new JSONArray();
			for (Group group : groups) {
				groupsJSON.add(group.toJson());
			}
			return groupsJSON;
		}
		return null;
	}

	public void addGroup(Group newGroup) {
		if (newGroup != null) {
			if (this.groups == null)
				this.groups = new HashSet<Group>();
			this.groups.add(newGroup);
		}
	}

	public byte[] getAvatar() {
		return this.avatar;
	}

	public void setAvatar(byte[] newAvatar) {
		avatar = newAvatar;
	}

	public int getRank() {
		return rank;
	}

	public void setRank(int newRank) {
		rank = newRank;
	}
	
	public void addCompletion(Completion makeCompletion) {
		completions.add(makeCompletion);
	}

	public int getTotalScore() {
		int totalScore = 0;
		for (Completion c: completions) {
			totalScore =  totalScore + c.getScore();
		}
		return totalScore;
	}

	public int getTotalCompletion() {
		return completions.size();
	}
	
	public JSONArray getJsonCompletions() {
		JSONArray completionsJSON = new JSONArray();
		for (Completion completion : completions) {
			JSONObject completionJSON = new JSONObject();
			completionJSON.put("puzzleName", completion.getPuzzleName());
			completionJSON.put("tries", completion.getTries());
			completionJSON.put("score", completion.getScore());
			completionsJSON.add(completionJSON);
		}
		return completionsJSON;
	}

	public int getTotalTries() {
		int totalTries = 0;
		for (Completion c: completions) {
			totalTries =  totalTries + c.getTries();
		}
		return totalTries;
	}

	public Set<Badge> getBadges() {
		return badges;
	}

	public JSONArray getJsonBadges() {
		if (badges == null)
			return null;
		JSONArray badgesJSON = new JSONArray();
		for (Badge badge : badges) {
			JSONObject badgeJSON = new JSONObject();
			badgeJSON.put("name", badge.getName());
			byte[] logo = badge.getLogo();
			if (logo != null)
				badgeJSON.put("logo", Base64.getEncoder().encodeToString(logo));
			badgeJSON.put("level", badge.getLevel());
			badgesJSON.add(badgeJSON);
		}
		return badgesJSON;
	}

	public void addBadge(Badge newBadge) {
		if (newBadge != null) {
			if (badges == null)
				badges = new HashSet<Badge>();
			badges.add(newBadge);
		}
	}

	@Override
	public int compareTo(Player other) {
		if (this == other)
			return 0;
		if (other == null)
			return -1;
		int compare = Integer.compare(other.getTotalScore(), getTotalScore());
		if (compare == 0) {
			compare = Integer.compare(other.getTotalCompletion(), getTotalCompletion());
			if (compare == 0) {
				compare = Integer.compare(getTotalTries(), other.getTotalTries());
				if (compare == 0)
					compare = other.getPseudo().compareTo(pseudo);
			}
		}

		return compare;
	}

	@Override
	public int hashCode() {
		return Objects.hash(email, pseudo);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Player other = (Player) obj;
		return Objects.equals(email, other.email) && Objects.equals(pseudo, other.pseudo);
	}
}
