package edu.uj.quizoff.client;

import edu.uj.quizoff.client.pojo.*;
import javafx.concurrent.*;
import javafx.geometry.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.control.Alert.*;
import javafx.scene.layout.*;
import javafx.scene.text.*;
import javafx.stage.*;

import java.io.*;

/**
 * Represents a screen shown while waiting for the server to pair players.
 *
 * @author Marcin Krzyszkowski
 */
public class SearchScreen extends Scene {

    private final Stage stage;

    private Label searchInfo;
    private ProgressIndicator searchProgressIndicator;
    private String category;
    private volatile Game game;

    public SearchScreen(Stage stage, double width, double height, String category) {
        super(new BorderPane(), width, height);
        this.stage = stage;
        this.category = category;
        initializeScreen((BorderPane)super.getRoot());
        dispatchRequestStartTask();
    }

    private void initializeScreen(BorderPane root) {
        searchInfo = new Label("Searching for an opponent...");
        searchInfo.setFont(Font.font(20));

        searchProgressIndicator = new ProgressIndicator(-1);
        searchProgressIndicator.setMinSize(100, 100);

        VBox searchBox = new VBox();
        searchBox.setPadding(new Insets(20));
        searchBox.setSpacing(10);
        searchBox.setAlignment(Pos.CENTER);
        searchBox.getChildren().addAll(searchInfo, searchProgressIndicator);

        root.setCenter(searchBox);
    }

    private void dispatchRequestStartTask() {
        Task<Boolean> task = new Task<Boolean>() {
            @Override
            protected Boolean call() throws ConnectionLostException {
                return (requestStart() || requestStart()); //taking advantage of short-circuit evaluation in order to search for opponent twice
            }
        };
        task.setOnSucceeded(event -> {
            if (task.getValue()) { //found opponent
                proceed();
            } else { //opponent not found
                Client.showAlert(AlertType.INFORMATION, "Could not find a worthy opponent. Try again.");
                back();
            }
        });
        task.setOnFailed(event -> Client.reloadOnConnectionLoss(stage)); //task fails when ConnectionLostException is thrown inside it
        new Thread(task).start();
    }

    private boolean requestStart() throws ConnectionLostException {
        Connection connection = Connection.getInstance();

        try {
            String data = Protocol.generateGameStartRequest(category);
            connection.sendData(data);
        } catch (IOException e) {
            return false;
        }

        try {
            String data = connection.receiveData();
            game = Protocol.convertGameStartResponse(data);
        } catch (IOException | ErrorReceivedException e) {
            return false;
        }

        return true;
    }

    private void back() {
        stage.setScene(new CategoryScreen(stage, getWidth(), getHeight()));
    }

    private void proceed() {
        stage.setScene(new GameScreen(stage, getWidth(), getHeight(), game));
    }
}
