package de.thdeg.greiner.superpangworld.graphics.base;

import de.thdeg.greiner.superpangworld.gameview.GameView;
import de.thdeg.greiner.superpangworld.graphics.moveable.Harpoon;
import de.thdeg.greiner.superpangworld.graphics.moveable.PlayerObject;

import java.util.*;

/**
 * A Bubble, which moves around on the screen and can be shot by the player.
 */
public abstract class Bubble extends CollidingGameObject implements MovingGameObject{

    /** Flag, if the bubble flies from left to right */
    private boolean flyFromLeftToRight;
    /** Random generator */
    private Random random;
    /** Flag, if the bubble is in the spawning phase */
    private boolean spawning;
    /** Spawning speed */
    private int spawnSpeed;
    /** Unique id for the spawn event timer */
    private long spawnID;
    /** Temporary movement action */
    private Position nextPosition;

    /**
     * Create a bubble with default values.
     *
     * @param gameView the {@link GameView} to display the bubble
     * @param objectsToCollideWith the list of {@link CollidableGameObject} the bubble can collide with
     */
    public Bubble(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith){
        super(gameView,objectsToCollideWith);
        rotation = 90;
        size = 10;
        width = (int) (12 * size);
        height = (int) (12 * size);
        speedInPixel = 1;
        flyFromLeftToRight = true;

        spawnID = UUID.randomUUID().getLeastSignificantBits();
        random = new Random();
        position.setTo(random.nextInt(GameView.WIDTH-width),-width);
        spawning = true;
        spawnSpeed = 500;
        gameView.setTimer("spawn"+spawnID,"bubble"+spawnID,spawnSpeed);

        nextPosition = new Position(random.nextInt(GameView.WIDTH-width),random.nextInt(GameView.HEIGHT-width));
    }

    /**
     * Create a bubble.
     * @param gameView the {@link GameView} to display the bubble
     * @param objectsToCollideWith the list of {@link CollidableGameObject} the bubble can collide with
     * @param size the object size
     * @param speedInPixel the speed in pixel per tick
     * @param position the position
     * @param spawning flag, if the bubble is in the spawning phase
     */
    public Bubble(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith, double size, double speedInPixel, Position position, boolean spawning){
        super(gameView,objectsToCollideWith);
        rotation = 90;
        this.size = size;
        width = (int) (12 * size);
        height = (int) (12 * size);
        this.speedInPixel = speedInPixel;
        flyFromLeftToRight = true;
        this.position.setTo(position.x,position.y);
        spawnID = UUID.randomUUID().getLeastSignificantBits();
        random = new Random();
        this.spawning = spawning;
        if(spawning){
            spawnSpeed = 500;
            gameView.setTimer("spawn"+spawnID,"bubble"+spawnID,spawnSpeed);
        }

        nextPosition = new Position(random.nextInt(GameView.WIDTH-width),random.nextInt(GameView.HEIGHT-width));
    }

    /**
     * Moves the bubble a tick further.
     */
    @Override
    public void updatePosition(){
        if(spawning){
            if(position.y >= 0){
                spawning = false;
            } else if(gameView.timerExpired("spawn"+spawnID,"bubble"+spawnID)){
                position.down(width/4);
                gameView.setTimer("spawn"+spawnID,"bubble"+spawnID,spawnSpeed);
            }
        }else{
            double distance = position.distance(nextPosition);
            if (distance >= speedInPixel) {
                position.right((nextPosition.x - position.x) / distance * speedInPixel);
                position.down((nextPosition.y - position.y) / distance * speedInPixel);
            } else {
                nextPosition = new Position(random.nextInt(GameView.WIDTH-width),random.nextInt(GameView.HEIGHT-width));
            }
        }


    }

    /**
     * Get the score to add when bursting the bubble.
     *
     * @return the score to add
     */
    public int getBurstScore(){
        return (int)(size*100);
    }

    /**
     * Get the size of the bubble.
     *
     * @return the size
     */
    public double getSize(){
        return this.size;
    }

    /**
     * Get the speed in pixel per tick
     * @return the speed in pixel per tick
     */
    public double getSpeedInPixel(){
        return speedInPixel;
    }

    @Override
    public void reactToCollision(CollidableGameObject otherObject) {
        if(otherObject instanceof PlayerObject){
            gamePlayManager.looseLife();
        }else if(otherObject instanceof Harpoon){
            gamePlayManager.destroy((Harpoon) otherObject);
            gamePlayManager.destroy(this);
        }
    }
}
