package brickbreaker;

import brickbreaker.Interfaces.BrickFactory;
import brickbreaker.Interfaces.GameObserver;
import brickbreaker.GameComponents.DefaultBrickFactory;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class GamePanel extends JPanel implements KeyListener, ActionListener {
    private boolean play = true;
    private int score = 0;

    private int totalBricks;
    private int rows = 10;
    private int columns = 14;

    private Timer timer;
    private int delay = 8;

    private int paddle = 310;

    private List<Ball> balls = new ArrayList<>(); // Use List interface instead of ArrayList

    private String font = "MV Boli";

    private GameMapBuilder map;

    public GamePanel() {
        Color color = Color.decode("#8B4513");
        this.balls.add(new Ball(350, 450, 2, -2, 20, color)); // Adjust the initial ball position and direction
        color = Color.decode("#008080");
        this.balls.add(new Ball(380, 420, -2, 2, 50, color));
        this.totalBricks = rows * columns;

        BrickFactory brickfactory = new DefaultBrickFactory();
        map = new GameMapBuilder(rows, columns, brickfactory);
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
        timer = new Timer(delay, this);
        timer.start();
    }

    private List<GameObserver> observers = new ArrayList<>();

    public void addObserver(GameObserver observer) {
        observers.add(observer);
    }

    public void removeObserver(GameObserver observer) {
        observers.remove(observer);
    }
    
    protected void paintComponent(Graphics graphics) {
        super.paintComponent(graphics);
        if (balls.isEmpty()) {
            gameOver(graphics, "Game Over", Color.BLACK);
        }   
        // background color
        graphics.setColor(Color.green);
        graphics.fillRect(1, 1, 692, 592);

        map.draw((Graphics2D) graphics);


        graphics.setColor(Color.blue);
        graphics.fillRect(paddle, 550, 100, 20);

        Iterator<Ball> ballsIterator = balls.iterator();

        while (ballsIterator.hasNext()) {
            Ball ball = ballsIterator.next();
            Vector ballPosition = ball.getPosition();

            if (ballPosition.y > 560) {
                ballsIterator.remove();
                continue;
            } else {
                ball.checkForWallCollisions();
            }

            ball.draw(graphics);
        }

        graphics.setColor(Color.black);
        graphics.setFont(new Font("MV Boli", Font.BOLD, 25));
        graphics.drawString("Score: " + score, 520, 30);

        if (totalBricks <= 0) {
            Color color = new Color(0XFF6464);
            gameOver(graphics, "You Won", color);
        }
        
        if (balls.isEmpty()) {
            gameOver(graphics, "Game Over", Color.BLACK);
        }

    }

    public void gameOver(Graphics graphics, String gameOverText, Color color) {
        play = false;
        graphics.setColor(color);
        graphics.setFont(new Font(font, Font.BOLD, 30));
        graphics.drawString(gameOverText + ", Your Score: " + score, 190, 300);

        graphics.setFont(new Font(font, Font.BOLD, 20));
        graphics.drawString("Press Enter to Restart", 230, 350);
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        if (play) {
            for (Ball ball : balls) {
                Vector ballPosition = ball.getPosition();
                Vector ballDirection = ball.getDirection();

                if (new Rectangle(ballPosition.x, ballPosition.y, ball.radius, ball.radius).intersects(new Rectangle(paddle, 550, 100, 8))) {
                    ballDirection.y = -ballDirection.y;
                    ball.setDirection(ballDirection.x, ballDirection.y);
                }

                for (int i = 0; i < map.map.length; i++) {
                    for (int j = 0; j < map.map[0].length; j++) {
                        if (map.map[i][j] > 0) {
                            int brickX = j * map.brickWidth;
                            int brickY = i * map.brickHeight;
                            int brickWidth = map.brickWidth;
                            int brickHeight = map.brickHeight;

                            Rectangle brickRect = new Rectangle(brickX, brickY, brickWidth, brickHeight);
                            Rectangle ballRect = new Rectangle(ballPosition.x, ballPosition.y, ball.radius, ball.radius);
                            
                            
                            if (ballRect.intersects(brickRect)) {
                                map.setBrickValue(0, i, j);
                                totalBricks--;
                                score += 5;

                                if (ballPosition.x + 19 <= brickRect.x || ballPosition.x + 1 >= brickRect.x + brickRect.width) {
                                    ballDirection.x = -ballDirection.x;
                                } else {
                                    ballDirection.y = -ballDirection.y;
                                }
                            }
                        }
                    }
                }
                ball.setDirection(ballDirection.x, ballDirection.y);
                ball.move(); // Call the move() method to update the ball's position
            }
        }

        repaint();
    }

    @Override
    public void keyTyped(KeyEvent arg0) {
    }

    @Override
    public void keyPressed(KeyEvent arg0) {
        if (arg0.getKeyCode() == KeyEvent.VK_RIGHT) {
            if (paddle >= 600) {
                paddle = 600;
            } else {
                moveRight();
            }
        }
        if (arg0.getKeyCode() == KeyEvent.VK_LEFT) {
            if (paddle < 10) {
                paddle = 10;
            } else {
                moveLeft();
            }
        }

        if (arg0.getKeyCode() == KeyEvent.VK_ENTER) {
            if (!play) {
                play = true;
                Color color = Color.decode("#8B4513");
                this.balls.add(new Ball(350, 450, 1, -1, 20, color)); // Adjust the initial ball position and direction
                score = 0;
                totalBricks = rows * columns;
                BrickFactory brickfactory = new DefaultBrickFactory();
                map = new GameMapBuilder(rows, columns, brickfactory);

                repaint();
            }
        }
    }

    public void moveRight() {
        play = true;
        paddle += 50;
    }

    public void moveLeft() {
        play = true;
        paddle -= 50;
    }

    @Override
    public void keyReleased(KeyEvent arg0) {
    }
}