package de.thdeg.greiner.superpangworld.game.managers;

import de.thdeg.greiner.superpangworld.gameview.GameView;
import de.thdeg.greiner.superpangworld.graphics.base.Bubble;
import de.thdeg.greiner.superpangworld.graphics.base.CollidableGameObject;
import de.thdeg.greiner.superpangworld.graphics.base.Position;
import de.thdeg.greiner.superpangworld.graphics.helper.Level;
import de.thdeg.greiner.superpangworld.graphics.helper.Player;
import de.thdeg.greiner.superpangworld.graphics.moveable.Harpoon;
import de.thdeg.greiner.superpangworld.graphics.moveable.HexagonalBubble;
import de.thdeg.greiner.superpangworld.graphics.moveable.RoundBubble;
import de.thdeg.greiner.superpangworld.graphics.moveable.SpecialBubble;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

/**
 * The manager which handles the gameplay.
 */
public class GamePlayManager {

    /** The GameView on which the game is displayed */
    private final GameView gameView;
    /** The manager, which handles the game objects */
    private final GameObjectManager gameObjectManager;
    /** Generator for random values */
    private final Random random;
    /** Das erste Level */
    private Level level;
    /** Der Spieler */
    private final Player player;

    /**
     * Create the manager handling the gameplay.
     *
     * @param gameView the GameView for visualization
     * @param gameObjectManager the manager handling the game objects
     */
    public GamePlayManager(GameView gameView, GameObjectManager gameObjectManager) {
        this.gameView = gameView;
        this.gameObjectManager = gameObjectManager;
        level = new Level(1,10000,10000);
        player = new Player(this.level);
        random = new Random();
        // Set HUD elements
        gameObjectManager.getPlayerObject().setGamePlayManager(this);
        gameObjectManager.getLevelLabel().setLevel(level.number);
        gameObjectManager.getLivesLabel().setLifeCount(player.lives);
        gameObjectManager.getScoreLabel().setScore(player.score);
    }

    /**
     * Handle the gameplay.
     */
    public void updateGamePlay(){
        if(gameView.timerExpired("SpawnBubble","GamePlayManager")){
            RoundBubble roundBubble = new RoundBubble(gameView, new ArrayList<>(Collections.singletonList(gameObjectManager.getPlayerObject())));
            roundBubble.setGamePlayManager(this);
            gameObjectManager.getBubbles().add(roundBubble);
            gameView.setTimer("SpawnBubble","GamePlayManager",3000);
        }
    }

    /**
     * Shoot a harpoon starting at a given position.
     *
     * @param startPosition the start position
     * @return if a harpoon was shot or not
     */
    public boolean shootHarpoon(Position startPosition){
        if(gameView.timerExpired("ShootHarpoon","GamePlayManager") && gameObjectManager.getHarpoons().size()<2){
            ArrayList<CollidableGameObject> collidableGameObjects = new ArrayList<>(gameObjectManager.getBubbles());
            Harpoon harpoon = new Harpoon(gameView,collidableGameObjects);
            harpoon.getPosition().setTo(startPosition.x+16, startPosition.y-15);
            harpoon.setGamePlayManager(this);
            gameObjectManager.getHarpoons().add(harpoon);
            gameView.setTimer("ShootHarpoon","GamePlayManager",300);
            return true;
        }
        return false;
    }

    /**
     * Remove a harpoon from the game.
     *
     * @param harpoon the harpoon to remove
     */
    public void destroy(Harpoon harpoon){
        gameObjectManager.getHarpoons().remove(harpoon);
    }

    /**
     * Remove a bubble from the game.
     *
     * @param bubble the bubble to remove
     */
    public void destroy(Bubble bubble){
        if(gameObjectManager.getBubbles().contains(bubble)) {
            if (bubble.getSize() > 1.25) {
                addRandomBubble(bubble.getSize() / 2, bubble.getSpeedInPixel(), bubble.getPosition(), false);
                addRandomBubble(bubble.getSize() / 2, bubble.getSpeedInPixel(), bubble.getPosition(), false);
            }

            gameObjectManager.getBubbles().remove(bubble);
            player.score += bubble.getBurstScore();
            updateHud();
            if(player.score>=level.neededOverallScore){
                switchLevel();
            }
        }
    }

    /**
     * Update all HUD elements
     */
    private void updateHud(){
        gameObjectManager.getScoreLabel().setScore(player.score);
        double progress = (player.score- level.neededOverallScore+ level.neededLevelScore * 1.0) / level.neededLevelScore;
        gameObjectManager.getLevelProgressBar().setLevelProgress(Math.min((int)(progress*100),100));
        gameObjectManager.getLevelLabel().setLevel(level.number);
    }

    /**
     * Switch the current level.
     */
    private void switchLevel(){
        if(level.number==99){
            System.out.println("You won!");
        }else{
            level = new Level(level.number+1,10000,(level.number+1)*10000);
            updateHud();
        }
    }

    /**
     * Add a random bubble with given values to the game. Percentages:
     *   - 60% normal bubble
     *   - 30% hexagonal bubble
     *   - 10% special bubble
     *
     * TODO: Integrate all different bubbles, not only the normal red bubble
     *
     * @param size the size of the bubble
     * @param speedInPixel the speed of the bubble
     * @param position the position of the bubble
     * @param spawning the flag if the bubble gets created in spawning mode
     */
    private void addRandomBubble(double size, double speedInPixel, Position position, boolean spawning){
        int randomNumber = random.nextInt(59);
        ArrayList<CollidableGameObject> collidableGameObjects = new ArrayList<>();
        collidableGameObjects.add(gameObjectManager.getPlayerObject());
        collidableGameObjects.addAll(gameObjectManager.getHarpoons());
        if(randomNumber<60){
            RoundBubble roundBubble = new RoundBubble(gameView, collidableGameObjects,size,speedInPixel,position,spawning);
            roundBubble.setGamePlayManager(this);
            gameObjectManager.getBubbles().add(roundBubble);
        }else if(randomNumber<90){
            HexagonalBubble hexagonalBubble = new HexagonalBubble(gameView, collidableGameObjects);
            hexagonalBubble.setGamePlayManager(this);
            gameObjectManager.getBubbles().add(hexagonalBubble);
        }else{
            SpecialBubble specialBubble = new SpecialBubble(gameView, collidableGameObjects);
            specialBubble.setGamePlayManager(this);
            gameObjectManager.getBubbles().add(specialBubble);
        }
    }

    /**
     * Loose a life and remove all bubbles
     */
    public void looseLife(){
        player.lives--;
        gameObjectManager.getLivesLabel().setLifeCount(player.lives);
        gameObjectManager.getBubbles().clear();
    }
}
