package com.lubjam16.epiceggsmash.game;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.graphics.g2d.ParticleEffect;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.lubjam16.epiceggsmash.EpicEggSmash;
import com.lubjam16.epiceggsmash.global.Fonts;
import com.lubjam16.epiceggsmash.mainMenu.MainMenu;

/**
 * Created by stonek on 1/30/16.
 */
public class GameScreen
        extends InputAdapter
        implements Screen {

    public static final int ADV_STEP = 20;
    private static final boolean BUTTON_Q = false;
    private static final boolean BUTTON_W = true;
    private static final boolean BUTTON_O = false;
    private static final boolean BUTTON_P = true;
    private static final float ADV_DEC_RATE = 20;

    private final EpicEggSmash game;

    private Viewport viewport;
    private SpriteBatch batch;
    private ShapeRenderer renderer;

    private int leftPlayerEggs;
    private int rightPlayerEggs;

    private boolean leftPlayerNextButton;
    private boolean rightPlayerNextButton;

    private int advantage;
    private float maxAdvantage;

    private GameState state;

    private float countdown;
    private GlyphLayout[] countdownCounterGL;
    private Vector2[] countdownCounterPosition;

    private GlyphLayout restartGameGL;
    private GlyphLayout restartRoundGL;
    private GlyphLayout quitGL;
    private GlyphLayout restartGameSelectedGL;
    private GlyphLayout restartRoundSelectedGL;
    private GlyphLayout quitSelectedGL;
    private GlyphLayout leftWinsGL;
    private GlyphLayout rightWinsGL;
    private GlyphLayout returnToMenuGL;
    private GlyphLayout noOneWinsGL;

    private Vector2 restartGamePosition;
    private Vector2 restartRoundPosition;
    private Vector2 quitPosition;
    private Vector2 restartGameSelectedPosition;
    private Vector2 restartRoundSelectedPosition;
    private Vector2 quitSelectedPosition;
    private Vector2 leftWinsPosition;
    private Vector2 rightWinsPosition;
    private Vector2 returnToMenuPosition;
    private Vector2 noOneWinsPosition;

    private GameMenuOption selectedOption;
    private int startingEggs;
    private Vector2 buttonXPosition;
    private Vector2 buttonZPosition;
    private Vector2 buttonPPosition;
    private Vector2 buttonOPosition;

    private boolean leftPressedWrong;
    private boolean rightPressedWrong;

    private Egg leftEgg;
    private Egg rightEgg;

    private float shakeLeft = -2;
    float renderAdvantage = 0;

    public GameScreen(EpicEggSmash epicEggSmash) {
        viewport = new FitViewport(MainMenu.WIDTH, MainMenu.HEIGHT);
        batch = new SpriteBatch();
        renderer = new ShapeRenderer();
        game = epicEggSmash;

        countdownCounterGL = new GlyphLayout[4];
        countdownCounterPosition = new Vector2[4];
        for(int i = 0; i < 4; i++){
            if(i==0){
                countdownCounterGL[i] = new GlyphLayout(Fonts.bigFont,"Smash!");
                countdownCounterPosition[i] =
                        new Vector2(400 - countdownCounterGL[i].width/2,550);
            }
            else{
                countdownCounterGL[i] = new GlyphLayout(Fonts.bigFont,""+i);
                countdownCounterPosition[i] =
                        new Vector2(400 - countdownCounterGL[i].width/2,350);
            }
        }
        leftEgg = new Egg(Egg.LEFT,this);
        rightEgg = new Egg(Egg.RIGHT,this);
    }

    public void init(int selectedEggs) {
        startingEggs = selectedEggs;
        state = GameState.READY;
        initReady(selectedEggs);
        initMenu();
        initCountdown();
        initRound();
        initButtonsPositions();
        initWinTexts();
    }

    private void initWinTexts() {
        leftWinsGL = new GlyphLayout(Fonts.bigFont,"Left player wins!");
        rightWinsGL = new GlyphLayout(Fonts.bigFont,"Right player wins!");
        noOneWinsGL = new GlyphLayout(Fonts.bigFont,"No one wins :(");
        returnToMenuGL = new GlyphLayout(Fonts.menuItemSelected,"[Back]");

        leftWinsPosition =
                new Vector2(400 - leftWinsGL.width/2,520);
        rightWinsPosition =
                new Vector2(400 - rightWinsGL.width/2,520);
        noOneWinsPosition =
                new Vector2(400 - noOneWinsGL.width/2,520);
        returnToMenuPosition =
                new Vector2(400 - returnToMenuGL.width/2,275);
    }

    private void initButtonsPositions() {
        buttonOPosition = new Vector2(800 - Graphics.buttonWActive.getWidth()*3,100);
        buttonPPosition = new Vector2(800 - Graphics.buttonWActive.getWidth()*2,100);
        buttonXPosition = new Vector2(Graphics.buttonWActive.getWidth()*2,100);
        buttonZPosition = new Vector2(Graphics.buttonWActive.getWidth(),100);
    }

    private void initRound() {
        advantage = 0;
        maxAdvantage = 300;
        leftEgg.init();
        rightEgg.init();
    }

    private void initMenu() {
        restartGameGL = new GlyphLayout(Fonts.menuItem,"Restart game");
        restartGameSelectedGL = new GlyphLayout(Fonts.menuItemSelected,"[Restart game]");
        restartRoundGL = new GlyphLayout(Fonts.menuItem,"Restart round");
        restartRoundSelectedGL = new GlyphLayout(Fonts.menuItemSelected,"[Restart round]");
        quitGL = new GlyphLayout(Fonts.menuItem, "Quit");
        quitSelectedGL = new GlyphLayout(Fonts.menuItemSelected,"[Quit]");

        restartRoundPosition =
                new Vector2(400 - restartGameGL.width/2,350);
        restartRoundSelectedPosition =
                new Vector2(400 - restartGameSelectedGL.width/2,350);
        restartGamePosition =
                new Vector2(400 - restartGameGL.width/2,300);
        restartGameSelectedPosition =
                new Vector2(400 - restartGameSelectedGL.width/2,300);
        quitPosition =
                new Vector2(400 - restartGameGL.width/2,250);
        quitSelectedPosition =
                new Vector2(400 - restartGameSelectedGL.width/2,250);
        selectedOption = GameMenuOption.RESTART_ROUND;
    }

    private void initCountdown() {
        leftPlayerNextButton = BUTTON_Q;
        rightPlayerNextButton = BUTTON_O;
        countdown = 3.5f;
    }

    private void initReady(int selectedEggs) {
        leftPlayerEggs = selectedEggs;
        rightPlayerEggs = selectedEggs;
    }

    @Override
    public void show() {
        Gdx.input.setInputProcessor(this);
    }

    @Override
    public void render(float delta) {
        viewport.apply();
        Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        batch.setProjectionMatrix(viewport.getCamera().combined);
        renderer.setProjectionMatrix(viewport.getCamera().combined);
        renderer.setAutoShapeType(true);

        batch.begin();
        renderer.begin();
        renderer.set(ShapeRenderer.ShapeType.Filled);

        batch.draw(Graphics.bg1,0,0);

        renderButtons(batch);
        renderAdvantageBar(renderer,delta);
        drawSmallEggs(batch);
        leftEgg.draw(batch,delta);
        rightEgg.draw(batch,delta);

        switch(state){
            case READY:
                state = GameState.COUNTDOWN;
                leftEgg.updateFight(delta);
                rightEgg.updateFight(delta);
                break;
            case INTRO:
                leftEgg.updateFight(delta);
                rightEgg.updateFight(delta);
                break;
            case COUNTDOWN:
                deltaCountdown(delta);
                leftEgg.updateFight(delta);
                rightEgg.updateFight(delta);
                break;
            case FIGHT_ON:
                deltaFithtOn(delta);
                Particles.orangeParticles.draw(batch,delta);
                Particles.purpleParticles.draw(batch,delta);
                leftEgg.updateFight(delta);
                rightEgg.updateFight(delta);
                break;
            case PAUSED:
                deltaPaused(batch);
                break;
            case OUTCOME:
                leftEgg.updateOutcome(delta);
                rightEgg.updateOutcome(delta);
                float shakeLeft2 = shakeLeft - delta;
                if(shakeLeft > 0 && shakeLeft2 < 0) {
                    viewport.getCamera().position.x = 400;
                    viewport.getCamera().position.y = 300;
                    if(leftPlayerEggs == 0 || rightPlayerEggs == 0){
                        state = GameState.FINAL;
                    }
                    else {
                        initCountdown();
                        initRound();
                        leftEgg.init();
                        rightEgg.init();
                        state = GameState.COUNTDOWN;
                    }
                }
                else if(shakeLeft > 0){
                    viewport.getCamera().position.x = (float) (400 + shakeLeft*Math.random()*4-2);
                    viewport.getCamera().position.y = (float) (300 + shakeLeft*Math.random()*4-2);
                }
                shakeLeft = shakeLeft2;

                break;
            case FINAL:
                if (rightPlayerEggs == 0 &&
                        leftPlayerEggs == 0){
                    Fonts.bigFont.draw(batch,
                            noOneWinsGL,
                            noOneWinsPosition.x,
                            noOneWinsPosition.y);
                }
                else if(rightPlayerEggs == 0){
                    Fonts.bigFont.draw(batch,
                            leftWinsGL,
                            leftWinsPosition.x,
                            leftWinsPosition.y);
                }
                else if (leftPlayerEggs == 0){
                    Fonts.bigFont.draw(batch,
                            rightWinsGL,
                            rightWinsPosition.x,
                            rightWinsPosition.y);
                }
                Fonts.menuItemSelected.draw(batch,
                        returnToMenuGL,
                        returnToMenuPosition.x,
                        returnToMenuPosition.y);
            default:
                break;
        }

        batch.end();
        renderer.end();
    }

    private void drawSmallEggs(SpriteBatch batch) {
        for(int i = 0; i < startingEggs; i++){
            if(i+1 > leftPlayerEggs){
                batch.draw(Graphics.smallLeftEggBroken, (1+i)*Graphics.smallLeftEggBroken.getWidth(),520);
            }
            else{
                batch.draw(Graphics.smallLeftEgg, (i+1)*Graphics.smallLeftEgg.getWidth(),520);
            }
            if(i+1 > rightPlayerEggs){
                batch.draw(Graphics.smallRightEggBroken, 800-(2+i)*Graphics.smallRightEgg.getWidth(),520);
            }
            else{
                batch.draw(Graphics.smallRightEgg, 800-(2+i)*Graphics.smallRightEgg.getWidth(),520);
            }
        }
    }

    private void renderAdvantageBar(ShapeRenderer renderer, float delta) {
        renderAdvantage = MathUtils.lerp(renderAdvantage, advantage, delta*15);

        renderer.setColor(Color.ORANGE);
        renderer.rectLine(400 + renderAdvantage, 50, 400 + maxAdvantage - 1, 50, 15);
        renderer.setColor(Color.PURPLE);
        renderer.rectLine(400 + renderAdvantage, 50, 400 - maxAdvantage, 50, 15);
    }

    private void renderButtons(SpriteBatch batch) {
        if(leftPlayerNextButton == BUTTON_W){
            batch.draw(Graphics.buttonWActive,
                    buttonXPosition.x,
                    buttonXPosition.y);
            if(leftPressedWrong){
                batch.draw(Graphics.buttonQWrong,
                        buttonZPosition.x,
                        buttonZPosition.y);
            }
            else{
                batch.draw(Graphics.buttonQInactive,
                        buttonZPosition.x,
                        buttonZPosition.y);
            }
        }
        else{
            batch.draw(Graphics.buttonQActive,
                    buttonZPosition.x,
                    buttonZPosition.y);
            if(leftPressedWrong){
                batch.draw(Graphics.buttonWWrong,
                        buttonXPosition.x,
                        buttonXPosition.y);
            }
            else{
                batch.draw(Graphics.buttonWInactive,
                        buttonXPosition.x,
                        buttonXPosition.y);
            }
        }

        if(rightPlayerNextButton == BUTTON_O){
            batch.draw(Graphics.buttonOActive,
                    buttonOPosition.x,
                    buttonOPosition.y);
            if(rightPressedWrong){
                batch.draw(Graphics.buttonPWrong,
                        buttonPPosition.x,
                        buttonPPosition.y);
            }
            else{
                batch.draw(Graphics.buttonPInactive,
                        buttonPPosition.x,
                        buttonPPosition.y);
            }
        }
        else{
            batch.draw(Graphics.buttonPActive,
                    buttonPPosition.x,
                    buttonPPosition.y);
            if(rightPressedWrong){
                batch.draw(Graphics.buttonOWrong,
                        buttonOPosition.x,
                        buttonOPosition.y);
            }
            else{
                batch.draw(Graphics.buttonOInactive,
                        buttonOPosition.x,
                        buttonOPosition.y);
            }
        }
    }

    private void deltaPaused(SpriteBatch batch) {
        switch(selectedOption){
            case RESTART_ROUND:
                Fonts.menuItemSelected.draw(batch,
                        restartRoundSelectedGL,
                        restartRoundSelectedPosition.x,
                        restartRoundSelectedPosition.y);
                Fonts.menuItem.draw(batch,
                        restartGameGL,
                        restartGamePosition.x,
                        restartGamePosition.y);
                Fonts.menuItem.draw(batch,
                        quitGL,
                        quitPosition.x,
                        quitPosition.y);
                break;
            case RESTART_GAME:
                Fonts.menuItem.draw(batch,
                        restartRoundGL,
                        restartRoundPosition.x,
                        restartRoundPosition.y);
                Fonts.menuItemSelected.draw(batch,
                        restartGameSelectedGL,
                        restartGameSelectedPosition.x,
                        restartGameSelectedPosition.y);
                Fonts.menuItem.draw(batch,
                        quitGL,
                        quitPosition.x,
                        quitPosition.y);
                break;
            case QUIT:
                Fonts.menuItem.draw(batch,
                        restartRoundGL,
                        restartRoundPosition.x,
                        restartRoundPosition.y);
                Fonts.menuItem.draw(batch,
                        restartGameGL,
                        restartGamePosition.x,
                        restartGamePosition.y);
                Fonts.menuItemSelected.draw(batch,
                        quitSelectedGL,
                        quitSelectedPosition.x,
                        quitSelectedPosition.y);
                break;
            default:
                break;
        }
    }

    private void deltaFithtOn(float delta) {
        if(countdown > -1.2) {
            countdown -= delta;
        }
        if(countdown > -1 && countdown < 0){
            Fonts.bigFont.draw(batch,
                    countdownCounterGL[0],
                    countdownCounterPosition[0].x,
                    countdownCounterPosition[0].y);
        }

        maxAdvantage -= delta*ADV_DEC_RATE;
        if(advantage == 0 && maxAdvantage <= 0){
            noOneWinsRound();
        }
        else if(advantage < maxAdvantage*-1){
            rightPlayerWinsRound();
        }
        else if(advantage > maxAdvantage){
            leftPlayerWinsRound();
        }

        for(int i = 0; i < 2; i++){
            Particles.purpleParticles.getEmitters().get(i)
                    .setPosition(400 - maxAdvantage,50);
            Particles.orangeParticles.getEmitters().get(i)
                    .setPosition(400 + maxAdvantage - 1, 50);
        }
    }

    private void noOneWinsRound() {
        state = GameState.OUTCOME;
        advantage = 0;
        leftPlayerEggs--;
        rightPlayerEggs--;
        rightEgg.winning = true;
        leftEgg.winning = true;
        leftEgg.state = EggState.EXPLODING;
        rightEgg.state = EggState.EXPLODING;
        leftEgg.initExplosion();
        rightEgg.initExplosion();
    }

    private void deltaCountdown(float delta) {
        countdown -= delta;
        if(countdown > 2 && countdown < 3){
            Fonts.bigFont.draw(batch,
                    countdownCounterGL[3],
                    countdownCounterPosition[3].x,
                    countdownCounterPosition[3].y);
        }
        else if(countdown > 1 && countdown < 2){
            Fonts.bigFont.draw(batch,
                    countdownCounterGL[2],
                    countdownCounterPosition[2].x,
                    countdownCounterPosition[2].y);
        }
        else if(countdown > 0 && countdown < 1){
            Fonts.bigFont.draw(batch,
                    countdownCounterGL[1],
                    countdownCounterPosition[1].x,
                    countdownCounterPosition[1].y);

        }
        else if(countdown > -1 && countdown < 0){
            state = GameState.FIGHT_ON;
            Particles.purpleParticles.start();
            Particles.orangeParticles.start();
            Particles.purpleParticles.reset();
            Particles.orangeParticles.reset();

        }
    }

    @Override
    public void resize(int width, int height) {
        viewport.update(width, height, true);
    }

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }

    @Override
    public void hide() {

    }

    @Override
    public void dispose() {
        batch.dispose();
    }

    public void onButtonQPress(){
        switch (state){
            case FIGHT_ON:
                if(leftPlayerNextButton == BUTTON_Q){
                    leftPlayerNextButton = BUTTON_W;
                    if(Math.abs(advantage += ADV_STEP) > maxAdvantage ){
                        leftPlayerWinsRound();
                    }
                    else {
                        advantage += ADV_STEP;
                    }
                }
                else{
                    leftPressedWrong = true;
                }
                break;
            default:
                break;
        }
    }

    public void onButtonWPress(){
        switch (state){
            case FIGHT_ON:
                if(leftPlayerNextButton == BUTTON_W){
                    leftPlayerNextButton = BUTTON_Q;
                    if(Math.abs(advantage += ADV_STEP) > maxAdvantage ){
                        leftPlayerWinsRound();
                    }
                    else {
                        advantage += ADV_STEP;
                    }
                }
                else{
                    leftPressedWrong = true;
                }
                break;
            default:
                break;
        }
    }

    public void onButtonPPress(){
        switch (state){
            case FIGHT_ON:
                if(rightPlayerNextButton == BUTTON_P){
                    rightPlayerNextButton = BUTTON_O;
                    if(Math.abs(advantage -= ADV_STEP) > maxAdvantage ){
                        rightPlayerWinsRound();
                    }
                    else {
                        advantage -= ADV_STEP;
                    }
                }
                else{
                    rightPressedWrong = true;
                }
                break;
            default:
                break;
        }
    }

    public void onButtonOPress(){
        switch (state){
            case FIGHT_ON:
                if(rightPlayerNextButton == BUTTON_O){
                    rightPlayerNextButton = BUTTON_P;
                    if(Math.abs(advantage -= ADV_STEP) > maxAdvantage ){
                        rightPlayerWinsRound();
                    }
                    else {
                        advantage -= ADV_STEP;
                    }
                }
                else{
                    rightPressedWrong = true;
                }
                break;
            default:
                break;
        }
    }

    private void rightPlayerWinsRound() {
        state = GameState.OUTCOME;
        advantage = (int) -maxAdvantage;
        leftPlayerEggs--;
        rightEgg.winning = true;
        leftEgg.state = EggState.MOVING;
        rightEgg.state = EggState.MOVING;
    }

    private void leftPlayerWinsRound() {
        state = GameState.OUTCOME;
        advantage = (int) maxAdvantage;
        rightPlayerEggs--;
        leftEgg.winning = true;
        leftEgg.state = EggState.MOVING;
        rightEgg.state = EggState.MOVING;
    }

    public void onButtonEnterPress(){
        switch (state){
            case PAUSED:
                switch (selectedOption){
                    case RESTART_GAME:
                        initReady(startingEggs);
                        initRound();
                        initCountdown();
                        state = GameState.READY;
                        break;
                    case RESTART_ROUND:
                        initRound();
                        initCountdown();
                        state = GameState.COUNTDOWN;
                        break;
                    case QUIT:
                        game.goToMainMenu();
                        break;
                    default:
                        break;
                }
                Sounds.menuSelected.play(0.55f);
                break;
            case FINAL:
                game.goToMainMenu();
                Sounds.menuSelected.play(0.55f);
                break;
            default:
                break;
        }
    }

    public void onButtonEscapePress(){
        switch(state){
            case READY:
                state = GameState.PAUSED;
                Sounds.menuSelected.play(0.55f);
                break;
            case FIGHT_ON:
                state = GameState.PAUSED;
                Sounds.menuSelected.play(0.55f);
                break;
            case COUNTDOWN:
                state = GameState.PAUSED;
                Sounds.menuSelected.play(0.55f);
                break;
            case INTRO:
                state = GameState.PAUSED;
                Sounds.menuSelected.play(0.55f);
                break;
            case FINAL:
                game.goToMainMenu();
                Sounds.menuSelected.play(0.55f);
                break;
            default:
                break;
        }
    }

    public void onButtonDownPress(){
        switch (state){
            case PAUSED:
                selectedOption = selectedOption.getNext();
                Sounds.menuChange.play(0.4f);
                break;
            default:
                break;
        }
    }

    public void onButtonUpPress(){
        switch (state){
            case PAUSED:
                selectedOption = selectedOption.getPrevious();
                Sounds.menuChange.play(0.4f);
                break;
            default:
                break;
        }
    }

    @Override
    public boolean keyDown(int keycode) {
        switch (keycode){
            case Input.Keys.ENTER:
                onButtonEnterPress();
                break;
            case Input.Keys.ESCAPE:
                onButtonEscapePress();
                break;
            case Input.Keys.UP:
                onButtonUpPress();
                break;
            case Input.Keys.DOWN:
                onButtonDownPress();
                break;
            case Input.Keys.Q:
                onButtonQPress();
                break;
            case Input.Keys.W:
                onButtonWPress();
                break;
            case Input.Keys.P:
                onButtonPPress();
                break;
            case Input.Keys.O:
                onButtonOPress();
                break;
        }

        return true;
    }

    @Override
    public boolean keyUp(int keycode) {
        rightPressedWrong = false;
        leftPressedWrong = false;

        return true;
    }

    public void setShake() {
        shakeLeft = 1.5f;
    }
}
