package edu.ntnu.stud.chaosgame.view;

import edu.ntnu.stud.chaosgame.controller.game.ChaosCanvas;
import edu.ntnu.stud.chaosgame.controller.game.ChaosGame;
import edu.ntnu.stud.chaosgame.controller.game.ChaosGameDescription;
import edu.ntnu.stud.chaosgame.model.generators.ChaosGameDescriptionFactory;

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.ToggleGroup;
import javafx.scene.control.RadioButton;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.scene.control.Button;
import javafx.util.Duration;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;

public class ChaosGameGUIView {
    private int currentLine = 0;

    private PixelWriter pixelWriter;

    private ImageView imageView;
    private int width;
    private int height;
    private ChaosGame game;

    private final Timeline timeline;



    public ChaosGameGUIView(Stage primaryStage) throws IOException {

        this.timeline = new Timeline(new KeyFrame(Duration.seconds(0.05), event -> this.drawChaosGame()));


        imageView = new ImageView();
        width = 1000;
        height = 1000;

        WritableImage writableImage = new WritableImage(width, height);
        pixelWriter = writableImage.getPixelWriter();

        imageView.setImage(writableImage);

        VBox sideMenu = new VBox();


        //TEMPORARY CODE to test Chaos Games in GUI

        ChaosGameDescriptionFactory factory = new ChaosGameDescriptionFactory();
        AtomicReference<ChaosGameDescription> description = new AtomicReference<>(factory.getDescriptions().get(0));
        ChaosCanvas canvas = new ChaosCanvas(1000, 1000, description.get().getMinCoords(), description.get().getMaxCoords());
        game = new ChaosGame(description.get(), canvas);

        Button startButton = new Button("Start");
        startButton.setOnAction(event -> timeline.play());
        Button stopButton = new Button("Stop");
        stopButton.setOnAction(event -> timeline.stop());


        Button newButton = new Button("New");

        newButton.setOnAction(event ->{
            WritableImage newWritableImage = new WritableImage(width, height);
            setPixelWriter(newWritableImage.getPixelWriter());
            setImageViewFromImage(newWritableImage);
            canvas.clearCanvas();
        });

        Button clearButton = new Button("Clear");

        clearButton.setOnAction(event -> {
            getImageView().setImage(null);
            setCurrentLine(0);
        });
        
        
        // Radio buttons for choosing fractal type
        ToggleGroup group = new ToggleGroup();
        RadioButton sierpinskiRadioButton = new RadioButton("Sierpinski");
        sierpinskiRadioButton.setToggleGroup(group);
        sierpinskiRadioButton.setSelected(true);
        RadioButton barnsleyRadioButton = new RadioButton("Barnsley");
        barnsleyRadioButton.setToggleGroup(group);
        RadioButton juliaRadioButton = new RadioButton("Julia");
        juliaRadioButton.setToggleGroup(group);

        AtomicReference<ChaosCanvas> canvasRef = new AtomicReference<>(canvas);
        sierpinskiRadioButton.setOnAction(event -> {
            timeline.stop();
            canvasRef.get().clearCanvas();
            WritableImage newWritableImage = new WritableImage(width, height);
            setPixelWriter(newWritableImage.getPixelWriter());
            setImageViewFromImage(newWritableImage);
            canvas.clearCanvas();

            description.set(factory.getDescriptions().get(0)); // Assuming the Sierpinski description is at index 0
            canvasRef.set(new ChaosCanvas(1000, 1000, description.get().getMinCoords(), description.get().getMaxCoords()));
            game = new ChaosGame(description.get(), canvasRef.get());
        });

        barnsleyRadioButton.setOnAction(event -> {
            timeline.stop();
            canvasRef.get().clearCanvas();
            WritableImage newWritableImage = new WritableImage(width, height);
            setPixelWriter(newWritableImage.getPixelWriter());
            setImageViewFromImage(newWritableImage);
            canvas.clearCanvas();
            description.set(factory.getDescriptions().get(1)); // Assuming the Sierpinski description is at index 0
            canvasRef.set(new ChaosCanvas(1000, 1000, description.get().getMinCoords(), description.get().getMaxCoords()));
            game = new ChaosGame(description.get(), canvasRef.get());
        });

        juliaRadioButton.setOnAction(event -> {
            timeline.stop();
            canvasRef.get().clearCanvas();
            WritableImage newWritableImage = new WritableImage(width, height);
            setPixelWriter(newWritableImage.getPixelWriter());
            setImageViewFromImage(newWritableImage);
            canvas.clearCanvas();
            description.set(factory.getDescriptions().get(2)); // Assuming the Sierpinski description is at index 0
            canvasRef.set(new ChaosCanvas(1000, 1000, description.get().getMinCoords(), description.get().getMaxCoords()));
            game = new ChaosGame(description.get(), canvasRef.get());
        });

        // Quit button
        Button quitButton = new Button("Quit");
        quitButton.setOnAction(event -> Platform.exit());

        // Add basic control buttons
        sideMenu.getChildren().addAll(startButton,stopButton,newButton,clearButton);
        // Add fractal radio buttons
        sideMenu.getChildren().addAll(sierpinskiRadioButton, barnsleyRadioButton, juliaRadioButton);
        // Add quit button
        sideMenu.getChildren().add(quitButton);



        BorderPane borderPane = new BorderPane();
        borderPane.setCenter(imageView);
        borderPane.setRight(sideMenu);

        Scene scene = new Scene(borderPane,1700,1000);

        primaryStage.setTitle("Fractal Chaos Game");
        primaryStage.setScene(scene);
        primaryStage.show();




    }

    public void drawChaosGame(){
        ChaosCanvas canvas = game.getCanvas();


        game.runSteps(100000);

        // Test implementation for drawing fractals
        int[][] betaArray = canvas.getCanvasArray();
        for (int i = 0; i < canvas.getWidth(); i++) {
            for (int j = 0; j < canvas.getHeight(); j++) {
                if (betaArray[i][j] == 1) {
                    pixelWriter.setColor(j,i,Color.BLACK);
                }
            }

        }



    }

    public int getWidth(){
        return this.width;
    }
    public int getHeight(){
        return this.height;
    }
    public ImageView getImageView(){
        return this.imageView;
    }

    public void setCurrentLine(int currentLine) {
        this.currentLine = currentLine;
    }

    public void setPixelWriter(PixelWriter pixelWriter) {
        this.pixelWriter = pixelWriter;
    }

    public void setImageViewFromImage(Image inputView) {
        this.imageView.setImage(inputView);
    }
}