package be.kdg.labyrinth.JavaFX.view;

import be.kdg.labyrinth.Game;
import be.kdg.labyrinth.JavaFX.model.GameModel;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.input.KeyCode;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

public class GamePresenter {
    private final GameModel model;
    private final GameView view;
    private Timeline timer;
    private long startTime;
    private final Stage stage;
    private List<Long> highscores;

    public GamePresenter(GameModel model, GameView view, Stage stage) {
        this.model = model;
        this.view = view;
        this.stage = stage;
        this.highscores = new ArrayList<>();

        startGameLoop();
        addEventHandlers();

        Platform.runLater(() -> { //dit is eigenlijk overbodig omdat we eerst een probleem hadden dat we niet konden bewegen.
            view.setFocusTraversable(true); //dit deel zorgt ervoor dat er focus is op de view.
            view.requestFocus();
        });

        stage.getScene().setOnMouseClicked(event -> view.requestFocus());
    }

    private void startGameLoop() {
        startTime = System.currentTimeMillis(); //geeft de huidige tijdstip
        timer = new Timeline(new KeyFrame(Duration.seconds(0.1), e -> updateView())); //keyframe wordt gebruikt om acties of animaties uit te voeren zoals in css. De actie wordt uitgevoerd om de 0.1seconden
        timer.setCycleCount(Timeline.INDEFINITE); //bepaalt hoe vaak de timeline wordt herhaald. Het wordt oneindig uitgevoerd totdat die wordt gestopt.
        timer.play();
    }

    private void updateView() { //zorgt ervoor dat het labyrinth wordt bijgewerkt
        char[][] labyrinth = model.getLabyrinth(); //de 2D array ophalen uit de LabyrinthModel
        int playerRow = model.getPlayerRow(); //halen de positie van de speler
        int playerCol = model.getPlayerCol();

        for (int row = 0; row < labyrinth.length; row++) { //gaat door elke rij en kolom in het labyrinth
            for (int col = 0; col < labyrinth[row].length; col++) {
                view.drawTile(row, col, labyrinth[row][col]); //roept de view methode op om elke tegel te gaan tekenen
            }
        }

        for (int[] pos : model.getTrail()) { //dit is eigenlijk overbodig omdat we hiervoor geen fotos hadden voor ons spel.
            if (labyrinth[pos[0]][pos[1]] != 'O') {
                view.drawTrail(pos[0], pos[1]);
            }
        }

        view.drawPlayer(playerRow, playerCol);

        view.updateTime(getElapsedTime());
        view.updatePlayerPosition(playerRow, playerCol);

        if (labyrinth[playerRow][playerCol] == 'E') { //controleert of de speler op het einde staat
            timer.stop(); //stop de tijd
            long elapsedTime = System.currentTimeMillis() - startTime; //berekent de tijd die nodig was.
            model.saveHighscore(elapsedTime, view.getPlayerName()); //highscore wordt dan opgeslagen in de scoremodel en in de gamemodel zodat die op beide shcermen kan komen
            Platform.runLater(this::showEndGameAlert); //toont het eindescherm.
        }
    }

    private void addEventHandlers() {
        view.setOnKeyPressed(event -> { //dit zorgt ervoor dat je kan bewegen
            KeyCode keyCode = event.getCode();

            view.updateKeypressedLabel(keyCode.toString());

            if (keyCode == KeyCode.Z || keyCode == KeyCode.UP) {
                model.movePlayer(-1, 0);
            } else if (keyCode == KeyCode.S || keyCode == KeyCode.DOWN) {
                model.movePlayer(1, 0);
            } else if (keyCode == KeyCode.Q || keyCode == KeyCode.LEFT) {
                model.movePlayer(0, -1);
            } else if (keyCode == KeyCode.D || keyCode == KeyCode.RIGHT) {
                model.movePlayer(0, 1);
            }

            view.requestFocus();
        });

        view.getBackButton().setOnAction(e -> { //een event zodat je terug naar het startschem kunt gaan.
            timer.stop(); //de tijd stopt
            StartView startView = new StartView(); //je maakt een nieuwe startview aan
            new StartPresenter(new GameModel("src/be/kdg/labyrinth/LabyrinthEasy.csv", "Easy"), startView, stage); //je roept de startpresenter aan omdat daar alle logica en de UI beheert wordt
            Scene scene = new Scene(startView, 1500, 800); //je maakt een scene aan voor alle UI elementen
            stage.setScene(scene); //daarna zorg je ervoor dat alles op het scherm wordt getoond
            stage.setFullScreen(false);
            stage.setResizable(true);
        });

        view.getAboutMenuItem().setOnAction(e -> {
            AboutView aboutView = new AboutView(false);
            new AboutPresenter(aboutView, new Stage()); // Nieuwe Stage aan de presenter geven

            Stage aboutStage = new Stage();
            aboutStage.setTitle("Over deze game");
            Scene scene = new Scene(aboutView, 800, 600);
            aboutStage.setScene(scene);
            aboutStage.setResizable(false);
            aboutStage.show();
        });

        view.getTutorialMenuItem().setOnAction(e -> {
            TutorialView tutorialView = new TutorialView(false);
            new TutorialPresenter(tutorialView, new Stage());
            Stage tutorialStage = new Stage();
            tutorialStage.setTitle("Tutorial");
            Scene scene = new Scene(tutorialView, 800, 600);
            tutorialStage.setScene(scene);
            tutorialStage.setResizable(false);
            tutorialStage.show();
        });
    }

    private String getElapsedTime() {
        long elapsedTime = System.currentTimeMillis() - startTime;
        return formatTime(elapsedTime);
    }

    private String formatTime(long millis) {
        int seconds = (int) (millis / 1000) % 60;
        int minutes = (int) ((millis / (1000 * 60)) % 60);
        int hours = (int) ((millis / (1000 * 60 * 60)) % 24);
        return String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }

    private void showEndGameAlert() {
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION); //CONFIRMATION zilt zeggen dat je kunt kiezen tussen ja en nee.
        alert.setTitle("Gewonnen!");
        alert.setHeaderText("Je hebt het einde bereikt!");
        alert.setContentText("Wil je opnieuw spelen?");

        ButtonType buttonTypeYes = new ButtonType("Ja");
        ButtonType buttonTypeNo = new ButtonType("Nee");

        alert.getButtonTypes().setAll(buttonTypeYes, buttonTypeNo); //vervangt de standaardknoppen door een ja en nee

        Optional<ButtonType> result = alert.showAndWait(); //toont de alert en wacht tot de gebruiker reageert en kiest daarna een knop van ButtonType.
        if (result.isPresent() && result.get() == buttonTypeYes) { //gebruiker kiest ja
            model.reset(); //reset het labyrinth
            startGameLoop(); //en word de tijd opnieuw gestart
        } else { //gebruiker kiest nee
            timer.stop(); //tijd stop
            StartView startView = new StartView();
            new StartPresenter(new GameModel("src/be/kdg/labyrinth/LabyrinthEasy.csv", "Easy"), startView, stage); //gebruiker gaat terug naar het startscherm
            Scene scene = new Scene(startView, 1500, 800);
            stage.setScene(scene);
            stage.setFullScreen(false);
            stage.setResizable(true);
        }
    }
}