package fr.insa.clavardator.client.users;

import fr.insa.clavardator.client.db.DatabaseController;
import fr.insa.clavardator.lib.users.User;
import fr.insa.clavardator.lib.users.UserInformation;
import fr.insa.clavardator.lib.util.ErrorCallback;
import fr.insa.clavardator.lib.util.Log;

import java.util.UUID;

public class CurrentUser extends User {
	private static CurrentUser instance = null;

	private State state;

	private CurrentUser() {
		super();
		state = State.UNINITIALIZED;
	}

	/**
	 * Returns the current.
	 */
	public static CurrentUser getInstance() {
		if (instance == null)
			instance = new CurrentUser();
		return instance;
	}

	private static String generateUniqueId() {
		return UUID.randomUUID().toString();
	}

	public void init(InitCallback callback, ErrorCallback errorCallback) {
		final DatabaseController db = new DatabaseController();
		db.getCurrentUser((user) -> {
			if (user == null) {
				setId(generateUniqueId());
				Log.v(getClass().getSimpleName(), "No previous user found, generating id: " + getId());
				db.addCurrentUser(
						new UserInformation(this),
						() -> {
							setState(State.NONE);
							callback.onFinish();
						},
						errorCallback);
			} else {
				setId(user.id);
				if (user.getUsername() != null) {
					Log.v(getClass().getSimpleName(), "Last user found : " + getId() + " / " + getUsername());
					setUsername(user.getUsername());
				} else {
					Log.v(getClass().getSimpleName(), "No username found, asking user");
					setState(State.NONE);
				}
				callback.onFinish();
			}
		}, errorCallback);
	}

	@Override
	public void setUsername(String newUsername) {
		super.setUsername(newUsername);
		final DatabaseController db = new DatabaseController();
		db.updateCurrentUsername(new UserInformation(this),
				null,
				e -> Log.e(getClass().getSimpleName(), "Unable to update the username", e));
		Log.v(this.getClass().getSimpleName(),
				"Username changed to " + getUsername());
		setState(State.VALID);
	}

	public State getState() {
		return state;
	}

	public void setState(State state) {
		Log.v(this.getClass().getSimpleName(),
				"State changed from " + this.state.toString() + " to " + state.toString());
		instance.getPcs().firePropertyChange("state", this.state, state);
		this.state = state;
	}

	public enum State {
		UNINITIALIZED,
		VALID,
		INVALID,
		NONE
	}

	public interface InitCallback {
		void onFinish();
	}
}
