package com.anibal.prueba_pooproyect;

import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.util.Random;

public class MainActivity extends AppCompatActivity {
    /////////////////////// CONSTANTES Y VALORES A UTILIZAR /////////////////////////
    final static int maxN = 15;
    final static int maxM = 20;
    private Context context;
    private int modo;
    private int playerNumbers;


    private ImageView[][] lvCell = new ImageView[maxM][maxN];

    private Drawable[] drawCell = new Drawable[8]; // 0 es vacia, 1,2,3, corresponde a los jugadores- esto se puede modificar! para aumentar la cantidad de estos
    private Drawable[] paintCell = new Drawable[4];

    private Button btnPlay;
    private TextView tvTurn;
    private android.support.v7.widget.AppCompatImageView resetGame;
    private android.support.v7.widget.AppCompatImageView goToMenu;
    private ImageView actualPlayerIcon;

    private int winner_play; // para ver ganador
    private boolean firstMove;
    private int xMove, yMove; // eje x e y
    private int turnPlay; // el turno de quien es¿?
    Board board = new Board(maxM, maxN);
    Game game = new Game(board, maxM, maxN);
    Bot_analisis comPlayer = new Bot_analisis(board,maxM,maxN);
    private int actualPlayer = 0;


    Dialog myDialog;


    ///////////////////////////////

    /////////////////////// ACA VIENE EL "MAIN"///////////////
    @Override
    /**
     * Metodo principal, aca se inicia el layout para jugar
     * notar que como parametro de getIntent llega el modo y el numero de jugadores.
     */
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().hide(); // esconder la barra con el nombre de la APP!
        setContentView(R.layout.activity_main);
        context = this;
        modo = getIntent().getIntExtra("PLAYING_MODE", 2);
        loadResources();
        designBoardGame(modo);
        playerNumbers = getIntent().getIntExtra("NUMBER_OF_PLAYERS", 2);
        setListen(modo);
        myDialog = new Dialog(this);





    }
    //main

    /**
     * metodo que setea los listeners para los botones de home y reset
     * @param modo = modo de juego (single o multiplayer)
     */
    private void setListen(final int modo) {

        tvTurn = findViewById(R.id.textingame);
        //tvTurn.setText("Press button Play Game");
        resetGame = findViewById(R.id.resetButton);
        goToMenu = findViewById(R.id.homeButton);

        init_game();
        board.clearBoard();
        winner_play = 0;
        if (modo == 1) {
            actualPlayer = 0;
        } else if (modo == 2) {
            actualPlayer = 0;
        }
        play_game(modo);
        goToMenu.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent menuActivity = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(menuActivity);
            }
        });

        resetGame.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                init_game();
                comPlayer.resetBoard();
                board.clearBoard();
                winner_play = 0;
                if (modo == 1) {

                } else if (modo == 2) {
                    actualPlayer = 0;
                }
                actualPlayerIcon.setImageDrawable(drawCell[actualPlayer + 1]);
                play_game(modo);
            }
        });


    }

    /**
     * metodo que se ocupa para iniciar el juego y setear las casillas con el color blanco
     */
    private void init_game() {

        // crea UI antes de empezar el juego! y setea jugadores
        tvTurn.setText("  Turno del Jugador:");
        firstMove = true;
        actualPlayerIcon.setImageDrawable(drawCell[actualPlayer + 1]);
        winner_play = 0;
        for (int i = 0; i < maxM; i++) {
            for (int j = 0; j < maxN; j++) {
                lvCell[i][j].setImageDrawable(drawCell[0]);
            }
        }

    }

    /**
     * Metodo que se ocupa para determinar quien inicia si es modo single, en modo multi no tiene mucha importancia.
     * @param modo
     */
    private void play_game(int modo) {
        if (modo == 1) {
            Random r = new Random();
            actualPlayer = r.nextInt(2);
            if (actualPlayer == 0) {
                Toast.makeText(context, "Player play first", Toast.LENGTH_SHORT).show();
                firstMove = false;
                playerTurn();

            } else {
                Toast.makeText(context, "Computer play first", Toast.LENGTH_SHORT).show();
                firstMove = true;
                botTurn(modo);

            }
        } else if (modo == 2) {

            playerTurn();

        }

    }

    /**
     * metodo que setea un flag de click en la pantalla falso mientras es el turno del humano
     */
    private void playerTurn() {
        //setear imagen del jugador
        isClicked = false;

    }

    /**
     * metodo importante encargado de segun es el primer movimiento de la partida o no decide como jugar el robot
     * @param modo modo en el que se juega, no tiene mucha relevancia en este metodo la verdad pero se ocupa en make_a_move();
     */
    private void botTurn(int modo) {
        /// /setear imagen de la computadora aca
        String move;
        boolean flagJugada = true;
        if (firstMove) { // dejo el if xq' quizas a futuro se ocupa
            System.out.println("lo logro");
            comPlayer.makeRandomMove(); // invoca el metodo para jugar random
            System.out.println("hizo random");
            xMove = comPlayer.getMovimientoCoordinates()[0];
            yMove = comPlayer.getMovimientoCoordinates()[1];
            move = xMove+" "+yMove;
            System.out.println(move);
            board.placeMove(actualPlayer+1,move,false);
            firstMove = false;
            make_a_move(modo);
        } else {
            System.out.println(xMove+" "+yMove+"ewads ");
            comPlayer.analizeBoard(board,xMove,yMove); // analizar el tablero para hacer la mejor jugada
            System.out.println("hizo movimiento");
            xMove = comPlayer.getMovimientoCoordinates()[0];
            yMove = comPlayer.getMovimientoCoordinates()[1];
            move = xMove+" "+yMove;
            board.placeMove(actualPlayer+1,move,false);
            System.out.println(move);
            make_a_move(modo);

            //buscar mejor movimiento (IA)
        }

    }

    /**
     * metodo para realizar la cuenta de los jugadores y si llega al maximo se resetea, es importante porque para pintar simbolos
     * y el tablero se utiliza el jugador actual como un numero.
     */
    private void nextPlayer() {
        actualPlayer++;
        if (actualPlayer == playerNumbers) actualPlayer = 0;
    }

    /**
     * metodo para realizar los movimientos, en la primera linea se ve como se setea el ImageDrawable correspondiente, tambien se ve
     * si hay un ganador antes de pasar al siguiente turno.
     * @param modo
     */
    private void make_a_move(int modo) {
        lvCell[xMove][yMove].setImageDrawable(drawCell[actualPlayer + 1]);
        if (game.isThereAwinner(actualPlayer + 1) == 0) { // no hay ganador
            if (modo == 1) { // vs bot
                if (actualPlayer == 0) {
                    nextPlayer();
                    botTurn(modo);
                } else if (actualPlayer == 1) {
                    nextPlayer();
                    playerTurn();
                }
            } else if (modo == 2) {
                nextPlayer();
            }//jugadores reales!
        }
        if (game.isThereAwinner(actualPlayer + 1) == 0) { // no hay ganador, es un poco redundante con lo de arriba
            winner_play = 0;
            //nextPlayer();
        } else { // hay ganador
            winner_play = actualPlayer + 1;
            tvTurn.setText("  Jugador ganador:");
            actualPlayerIcon.setImageDrawable(drawCell[actualPlayer + 1]);
            // aca cambiar la wea y poner el jugador ganador en la cruz! tvTurn y wea
            paintWhenWinner();
            new Thread(new Runnable() { //thread correspondiente al popup de ganador
                @Override
                public void run() {
                    runOnUiThread(new Runnable() { //necesario segun la documentacion para funcionamiento
                        // si no esta falla brutalmente
                        @Override
                        public void run() {
                            showWinnerPopUp();
                        }
                    });
                }
            }).start();

        }

        actualPlayerIcon.setImageDrawable(drawCell[actualPlayer + 1]);
        isClicked = false;

    }

    /**
     * metodo encargado de mostrar el PopUp cuando hay un ganador y setear su listener para cerrarlo.
     */
    private void showWinnerPopUp() {
        ImageView ganador;
        TextView closePopUp;
        myDialog.setContentView(R.layout.custompopupmenuwinner);

        ganador = myDialog.findViewById(R.id.jugadorGanador);
        ganador.setBackgroundColor(0); // le quita el color a la cruz del jugador, sin esto se ve un pequeño destello negro al rededor de esta!
        ganador.setImageDrawable(drawCell[actualPlayer + 1]);
        closePopUp = (TextView) myDialog.findViewById(R.id.closePopUp);
        closePopUp.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myDialog.dismiss();
            }
        });
        myDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        myDialog.show();
    }

    /**
     * cuando hay un ganador este se encarga de ver desde game como se gano, es decir, en que direccion y en que coordenadas, para
     * realizar el pintado de ese jugador en esa posicion en la direccion establecida.
     */
    private void paintWhenWinner() {
        String howItWon = game.getHowWonTheGame();
        int[] winnerCoordinates = game.getWinnerCoordinates();
        if (howItWon == "COL") {
            for (int i = 0; i < 5; i++) {
                lvCell[winnerCoordinates[0]][winnerCoordinates[1] + i].setImageDrawable(paintCell[actualPlayer]);


            }

        } else if (howItWon == "ROW") {
            for (int i = 0; i < 5; i++) {
                lvCell[winnerCoordinates[0] + i][winnerCoordinates[1]].setImageDrawable(paintCell[actualPlayer]);

            }

        } else if (howItWon == "LD") {
            for (int i = 0; i < 5; i++) {
                lvCell[winnerCoordinates[0] + i][winnerCoordinates[1] - i].setImageDrawable(paintCell[actualPlayer]);

            }

        } else if (howItWon == "RD") {
            for (int i = 0; i < 5; i++) {
                lvCell[winnerCoordinates[0] + i][winnerCoordinates[1] + i].setImageDrawable(paintCell[actualPlayer]);

            }

        }


    }

    /**
     * metodo importante encargado de precargar los recursos graficos a utilizar, basicamente las celdas, los jugadores y
     * los colores para cuando se gana
     */
    private void loadResources() {
        drawCell[0] = null;
        drawCell[1] = context.getResources().getDrawable(R.drawable.circulo_amarillo_player); // primer player
        drawCell[2] = context.getResources().getDrawable(R.drawable.circulo_naranjo_player); // segundo player
        drawCell[3] = context.getResources().getDrawable(R.drawable.circulo_morado_player); // tercer player
        drawCell[4] = context.getResources().getDrawable(R.drawable.circulo_grisoscuro_player); // cuarto player
        drawCell[5] = context.getResources().getDrawable(R.drawable.cruz_gris);  //quinto player - cambiar el color de este XD
        drawCell[6] = context.getResources().getDrawable(R.drawable.cruz_verde); //bot en caso de
        drawCell[7] = context.getResources().getDrawable(R.drawable.cell_bg); // fondo
        paintCell[0] = context.getResources().getDrawable(R.drawable.fondo_amarillo); // CAMBIAR ESTE COLOR
        paintCell[1] = context.getResources().getDrawable(R.drawable.fondo_naranjosalmon);
        paintCell[2] = context.getResources().getDrawable(R.drawable.fondo_color_morado);
        paintCell[3] = context.getResources().getDrawable(R.drawable.fondo_gris_oscura);
    }

    private boolean isClicked;

    /**
     * Metodo imporatntisimo, este crea los LinearLayouts dentro del tablero y setea los listeners para este, es decir, crea
     * el tablero n*m y los n*m listeners, uno para cada cuadrado
     * @param modo
     */

    @SuppressLint("NewApi")
    private void designBoardGame(int modo) {
        actualPlayerIcon = findViewById(R.id.imagenJugadorActual);
        LinearLayout linBoardGame = (LinearLayout) findViewById(R.id.linBoardGame);
        int sizeofCell = Math.round(ScreenWidth() / maxN - dpToPx(1)); // el factor de dptoPx ayuda a que quede con mas margen el tablero
        LinearLayout.LayoutParams lpRow = new LinearLayout.LayoutParams(sizeofCell * maxN, sizeofCell);
        LinearLayout.LayoutParams lpCell = new LinearLayout.LayoutParams(sizeofCell, sizeofCell);


        //creacion de las celdas
        for (int i = 0; i < maxM; i++) {
            LinearLayout linRow = new LinearLayout(context);
            // se hace una fila
            for (int j = 0; j < maxN; j++) {
                lvCell[i][j] = new ImageView(context);
                //creando una celda

                lvCell[i][j].setBackground(drawCell[7]);

                final int x = i;
                final int y = j;
                final int modoDeJuego = modo;
                final String move = x + " " + y; // string del movimiento para comparar
                lvCell[i][j].setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                if (!isClicked && board.getEmpties().contains(move)
                                        && winner_play == 0) { //human turn
                                    isClicked = true;
                                    xMove = x;
                                    yMove = y;
                                    String move = xMove + " " + yMove;
                                    board.placeMove(actualPlayer + 1, move, false); // aca el parametro booleano es para hacer que imprima o no la jugada, util para debuggear

                                    runOnUiThread(new Runnable() { //necesario segun la documentacion para funcionamiento
                                        // si no esta falla brutalmente al hacer click
                                        @Override
                                        public void run() {
                                            make_a_move(modoDeJuego);
                                        }
                                    });

                                }
                            }
                        }).start();

                    }
                });

                linRow.addView(lvCell[i][j], lpCell);

            }
            linBoardGame.addView(linRow, lpRow);


        }

    }

    /**
     * metodo importante para obtener el ancho de la pantalla y poder calzar la dimension de los cuadrados del tablero
     * con el numero de estos
     * @return la en pixeles del ancho de la pantalla.
     */
    private float ScreenWidth() {
        Resources resources = context.getResources();
        DisplayMetrics dn = resources.getDisplayMetrics();
        return dn.widthPixels;

    }

    /**
     * metodo para convertir dp, unidad "generica" de la pantalla (se ajusta segun esta) a pixeles y poder realizar ajustes,
     * es utilizada en el diseño del tablero
     * @param dp = dp's de entrada
     * @return cantidad de pixeles equivalente a esos dp's
     */
    public int dpToPx(int dp) {
        float density = context.getResources()
                .getDisplayMetrics()
                .density;
        return Math.round((float) dp * density);
    }
}