package fr.insa.clavardator.client.ui.chat;

import fr.insa.clavardator.client.chat.ChatHistory;
import fr.insa.clavardator.client.ui.LoadingScreenController;
import fr.insa.clavardator.client.users.PeerUser;
import fr.insa.clavardator.lib.message.Message;
import fr.insa.clavardator.lib.util.ErrorCallback;
import fr.insa.clavardator.lib.util.Log;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;

import java.net.URL;
import java.util.ResourceBundle;

/**
 * Controller for the chat window
 */
public class ChatController implements Initializable {

	@FXML
	private ListView<Message> messageList;
	@FXML
	private ChatFooterController chatFooterController;
	@FXML
	private ChatHeaderController chatHeaderController;
	@FXML
	private LoadingScreenController loadingController;
	@FXML
	private VBox chatContainer;
	@FXML
	private VBox emptyContainer;
	private PeerUser remoteUser;

	//	public void setAttachmentListener(ButtonPressEvent listener) {
//		chatFooterController.setAttachmentListener(listener);
//	}
	public void setSendErrorListener(ErrorCallback listener) {
		chatFooterController.setSendErrorListener(listener);
	}

	/**
	 * Check the user that finished loading is the right one then set the chat state to done
	 *
	 * @param user The user that finished loading
	 */
	private void onHistoryLoaded(PeerUser user) {
		if (user.equals(remoteUser)) {
			setState(State.DONE);
			scrollToEnd();
		}
	}

	/**
	 * Sets the remote user to chat with and subscribe to its messages
	 *
	 * @param remoteUser The user to chat with
	 */
	public void setRemoteUser(PeerUser remoteUser) {
		this.chatFooterController.setRemoteUser(remoteUser);
		this.chatHeaderController.setRemoteUser(remoteUser);
		setState(State.LOADING);

		this.remoteUser = remoteUser;
		final ChatHistory history = remoteUser.getHistory();
		history.setHistoryLoadedListener(this::onHistoryLoaded);
		messageList.setItems(history.getHistory());
		messageList.getItems().addListener((ListChangeListener<? super Message>) (c) -> {
			c.next();
			// Make sure we always have the latest item on screen
			scrollToEnd();
		});
		history.load(e -> Log.e(getClass().getSimpleName(), "Error while loading message", e)/* TODO: show an error message? */);
	}

	/**
	 * Scroll to the end of the message list
	 */
	private void scrollToEnd() {
		final int size = messageList.getItems().size();
		if (size > 0) {
			Platform.runLater(() -> messageList.scrollTo(size - 1));
		}
	}

	/**
	 * Sets the chat state.
	 * <ul>
	 *   <li>
	 *     On Initial state, show an empty screen
	 *   </li>
	 *   <li>
	 *     on Loading state, show the loading screen
	 *   </li>
	 *   <li>
	 *     on Done state, show the chat
	 *   </li>
	 * </ul>
	 *
	 * @param state The new state to set
	 */
	private void setState(State state) {
		switch (state) {
			case INITIAL:
				emptyContainer.setVisible(true);
				chatContainer.setVisible(false);
				loadingController.hide();
				messageList.setItems(null);
				break;
			case LOADING:
				chatContainer.setVisible(true);
				loadingController.show();
				emptyContainer.setVisible(false);
				break;
			case DONE:
				chatContainer.setVisible(true);
				emptyContainer.setVisible(false);
				loadingController.hide();
				break;
		}
	}

	@Override
	public void initialize(URL url, ResourceBundle rb) {
		loadingController.getRootStyle().clear();
		loadingController.getRootStyle().add("inner");
		messageList.setSelectionModel(new NoSelectionModel<>());
		messageList.setCellFactory(listView -> new MessageListItemCell());
		setState(State.INITIAL);
	}

	private enum State {
		INITIAL,
		LOADING,
		DONE
	}

}