import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class SpaceInvadersModel {
    private static final int WIDTH = 800;
    private static final int HEIGHT = 600;

    private static final int SPACESHIP_WIDTH = 50;
    private static final int SPACESHIP_HEIGHT = 50;

    private static final int ENEMY_WIDTH = 50;
    private static final int ENEMY_HEIGHT = 50;

    private static final int BULLET_WIDTH = 10;
    private static final int BULLET_HEIGHT = 10;

    private static final int SPACESHIP_SPEED = 5;
    private long lastShotTime;
    private static final int SHOT_COOLDOWN = 200;

    private final Image spaceshipImage;
    private final Image enemyImage;
    private final Image bulletImage;
    private final Image backgroundImage;
    private final Image heartImage;

    private int spaceshipX;
    private final int spaceshipY;
    private int score;
    private int scoreUnitIncrease;
    private final int health;
    private double dy = 10;
    private int levelCounter;

    private boolean movingLeft;
    private boolean movingRight;
    private boolean shooting;

    private List<Enemy> enemies;
    private List<Bullet> bullets;

    public SpaceInvadersModel() {
        levelCounter = 1;
        running = false;
        score = 0;
        scoreUnitIncrease = 10;
        health = 3;
        heartImage = new ImageIcon("resources/heart.png").getImage();
        spaceshipImage = new ImageIcon("resources/spaceship.png").getImage();
        enemyImage = new ImageIcon("resources/enemy.png").getImage();
        bulletImage = new ImageIcon("resources/bullet.png").getImage();
        backgroundImage = new ImageIcon("resources/background.png").getImage();
        lastShotTime = 0;

        spaceshipX = WIDTH / 2 - SPACESHIP_WIDTH / 2;
        spaceshipY = HEIGHT - SPACESHIP_HEIGHT - 10;

        enemies = new ArrayList<>();
        bullets = new ArrayList<>();

        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 10; j++) {
                enemies.add(new Enemy(j * ENEMY_WIDTH + 50, i * ENEMY_HEIGHT + 50, dy));
            }
        }
    }

    public void startShooting() {
        shooting = true;
    }

    public void stopShooting() {
        shooting = false;
    }

    public Image getSpaceshipImage() {
        return spaceshipImage;
    }

    public Image getEnemyImage() {
        return enemyImage;
    }

    public Image getBulletImage() {
        return bulletImage;
    }

    public Image getBackgroundImage() {
        return backgroundImage;
    }

    public Image getHeartImage() {
        return heartImage;
    }

    public int getHealth() {
        return health;
    }

    public int getSpaceshipX() {
        return spaceshipX;
    }

    public int getSpaceshipY() {
        return spaceshipY;
    }

    public List<Enemy> getEnemies() {
        return enemies;
    }

    public List<Bullet> getBullets() {
        return bullets;
    }

    public int getScore() {
        return score;
    }

    public static int getWidth() {
        return WIDTH;
    }

    public int getLevelCounter() {
        return levelCounter;
    }

    public void setLevelCounter(int levelCounter) {
        if(levelCounter < 6 && levelCounter > 0) {
            this.levelCounter = levelCounter;
        }
    }

    public void setScore(int score) {
        this.score += score;
    }

    public void setScoreUnitIncrease(int scoreUnitIncrease) {
        this.scoreUnitIncrease = scoreUnitIncrease;
    }

    public void setMovingLeft(boolean movingLeft) {
        this.movingLeft = movingLeft;
    }

    public void setMovingRight(boolean movingRight) {
        this.movingRight = movingRight;
    }

    private boolean running;

    public void setRunning(boolean running) {
        this.running = running;
    }

    public void resetGameState() {
        spaceshipX = WIDTH / 2 - SPACESHIP_WIDTH / 2;

        score = 0;
        enemies.clear();
        bullets.clear();

        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 10; j++) {
                enemies.add(new Enemy(j * ENEMY_WIDTH + 50, i * ENEMY_HEIGHT + 50, dy));
            }
        }
    }

    public void nextLevel() {
        spaceshipX = WIDTH / 2 - SPACESHIP_WIDTH / 2;
        if(dy < 31) {
            dy += 5;
        }

        enemies.clear();
        bullets.clear();

        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 10; j++) {
                enemies.add(new Enemy(j * ENEMY_WIDTH + 50, i * ENEMY_HEIGHT + 50, dy));
            }
        }
    }

    public void previousLevel() {
        spaceshipX = WIDTH / 2 - SPACESHIP_WIDTH / 2;

        if(dy - 5 > 9)
        {
            dy -= 5;
        }

        enemies.clear();
        bullets.clear();

        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 10; j++) {
                enemies.add(new Enemy(j * ENEMY_WIDTH + 50, i * ENEMY_HEIGHT + 50, dy));
            }
        }
    }

    public void update() {
        if (running) {
            if (movingLeft && spaceshipX > 0) {
                spaceshipX -= SPACESHIP_SPEED;
            }
            if (movingRight && spaceshipX < WIDTH - SPACESHIP_WIDTH) {
                spaceshipX += SPACESHIP_SPEED;
            }

            if (shooting && System.currentTimeMillis() - lastShotTime >= SHOT_COOLDOWN) {
                Bullet bullet = new Bullet(spaceshipX + SPACESHIP_WIDTH / 2 - BULLET_WIDTH / 2, spaceshipY - BULLET_HEIGHT);
                bullets.add(bullet);
                lastShotTime = System.currentTimeMillis();
            }

            double leftmostEnemyX = Integer.MAX_VALUE;
            double rightmostEnemyX = Integer.MIN_VALUE;
            for (Enemy enemy : enemies) {
                enemy.update();
                leftmostEnemyX = Math.min(leftmostEnemyX, enemy.getX());
                rightmostEnemyX = Math.max(rightmostEnemyX, enemy.getX() + ENEMY_WIDTH);
            }

            if (leftmostEnemyX <= 0 || rightmostEnemyX >= WIDTH) {
                for (Enemy enemy : enemies) {
                    enemy.setDx(-enemy.getDx());
                }
            }

            bullets = bullets.stream().filter(b -> {
                b.update();
                boolean removeBullet = b.getY() < 0;
                if (!removeBullet) {
                    for (Enemy e : enemies) {
                        if (e.getX() < b.getX() + BULLET_WIDTH && e.getX() + ENEMY_WIDTH > b.getX() && e.getY() < b.getY() + BULLET_HEIGHT && e.getY() + ENEMY_HEIGHT > b.getY()) {
                            setScore(scoreUnitIncrease);
                            e.setDead(true);
                            removeBullet = true;
                            break;
                        }
                    }
                }
                return !removeBullet;
            }).collect(Collectors.toList());

            enemies = enemies.stream().filter(e -> !e.isDead()).collect(Collectors.toList());
        }
    }
}