import processing.core.PApplet;
import processing.core.PImage;

import java.util.LinkedList;
import java.util.List;

public class GraphicsProgram extends PApplet {

    private LinkedList<int[]> player1Trail = new LinkedList<>(); // Liste für Spieler 1
    private LinkedList<int[]> player2Trail = new LinkedList<>(); // Liste für Spieler 2

    private final int TRAIL_LENGTH = 150;
    private int trailCounter = 17;

    private int distanceTh = 100;

    private int gameState = 0; //0 für Welcome, 1 für Morphing, 2 für Game, 3 für Gameover

    private float startingTime = System.currentTimeMillis();

    PImage img1;
    PImage img2;
    PImage backgroundImage;

    LinkedList<PImage> cameraLoadingImages = new LinkedList<>();

    public static void main(String[] args) {
        PApplet.main("GraphicsProgram");
    }

    public void settings() {
        fullScreen();
    }

    public void setup() {
        backgroundImage = loadImage("Background.png");
        backgroundImage.resize(1792, 1024);

        img1 = loadImage("TrailBlue.png");
        img2 = loadImage("TrailRed.png");

        cameraLoadingImages.add(loadImage("Welcome0.png"));
        cameraLoadingImages.add(loadImage("Welcome1.png"));
        cameraLoadingImages.add(loadImage("Welcome2.png"));
        cameraLoadingImages.add(loadImage("Welcome3.png"));
    }

    public void draw() {
        if (gameState == 0) {
            drawWelcome();
        }
        if (gameState == 1) {
            setUpMorphing();
        }
        if (gameState == 2) {
            gameScreen();
        }
        if (gameState == 3) {
            gameOverScreen();
        }
    }

    public void drawWelcome() {
        int waitingTime = (int) (System.currentTimeMillis() / 1000);
        switch (waitingTime % 4) {
            case 0:
                image(cameraLoadingImages.get(0), 0, 0);
                break;
            case 1:
                image(cameraLoadingImages.get(1), 0, 0);
                break;
            case 2:
                image(cameraLoadingImages.get(2), 0, 0);
                break;
            case 3:
                image(cameraLoadingImages.get(3), 0, 0);
        }
    }

    private void setUpMorphing() {
    }

    private void gameScreen() {
        image(backgroundImage, 0, 0); // Hintergrund zeichnen
        strokeWeight(20); // Linienstärke festlegen
        // Linien für Spieler 1 zeichnen
        stroke(0, 0, 255); // Blau
        drawTrail(player1Trail, 1);
        // Linien für Spieler 2 zeichnen
        stroke(255, 0, 0); // Rot
        drawTrail(player2Trail, 2);
    }

    private void gameOverScreen() {
    }

    public void nextGameState() {
        gameState++;
    }

    // Methode, um Linien für eine gegebene Trail-Liste zu zeichnen
    private void drawTrail(LinkedList<int[]> trail, int player) {
        if (trail.size() < 4) return; // Mindestens 2 Punkte nötig, um Linien zu zeichnen

        for (int i = 0; i < trail.size() - 1; i++) {
            if (player == 1){
                stroke(170-(255/trail.size() * i),0,255/2 + (255/trail.size() * i)/2);
            } else if (player == 2){
                stroke(255, 170-(255/trail.size() * i), 0);
            }
            int[] current = new int[2];
            try {
                current = trail.get(i);
            } catch (NullPointerException e) {
                System.out.println("Index 1 out of bounds");
                continue;
            }

            int[] next = new int[2];
            try {
                next = trail.get(i + 1);
            } catch (NullPointerException e) {
                System.out.println("Index 2 out of bounds");
                continue;
            }

            // Null-Check für die Punkte
            if (current != null && next != null) {
                if (current[0] - next[0] > -distanceTh && current[0] - next[0] < distanceTh && current[1] - next[1] > -distanceTh && current[1] - next[1] < distanceTh) {
                    line(current[0], current[1], next[0], next[1]);
                }
            }
        }
    }


    // Methode zum Aktualisieren der Trails für beide Spieler
    public void updateTrail(int x1, int y1, int x2, int y2) {
        if (x1 >= 0 && y1 >= 0) {
            addToTrail(player1Trail, x1, y1);
        }
        if (x2 >= 0 && y2 >= 0) {
            addToTrail(player2Trail, x2, y2);
        }
    }

    // Methode zum Hinzufügen eines Punktes zur Trail-Liste und Begrenzung auf 20 Einträge
    private void addToTrail(LinkedList<int[]> trail, int x, int y) {
        if (trailCounter % 7 == 0) {
            if (x >= 0 && y >= 0) {
                trail.add(new int[]{x, y});
                if (trail.size() > TRAIL_LENGTH) {
                    trail.removeFirst();
                }
            }
        }
        trailCounter++;
    }


}