package jeu;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import entity.Boss;
import entity.Character;
import entity.Hearth;
import entity.Kunai;
import entity.Monster;
import entity.ShootingCharacter;
import engine.Game;
import environnement.Coordonnees;
import environnement.HitBox;
import map.Obstacle;
import loaders.CharacterLoader;
import map.Coffre;
import map.LevelManager;


public class Jeu implements Game{

    //coordonnees du sol
    //private static Coordonnees coordSol = new Coordonnees(200,700); //coordonnees du sol (en realite juste Z nous interesse)


    //Coordonees de debut du personnage
    static final double zdebut = 300;
    static final double xdebut = 700;

    //perso
    static Character gameCharacter;

    //recupere la direction dans laquelle doit aller le personnage
    private static Map<String,Boolean> directionJeu;

    //celui qui chargera le perso et les sprites
    static CharacterLoader gameCharacterLoader;

    //path vers la bonne frame a utiliser
    String characterSkinPath; 
    //sa construction
    final String beginPath;
    String movement;

    //pour pouvoir se souvenir de l'ancien mouvement effectue
    String previousMovement;

    //gere le chgt de frame
    int numberOfMovement;
    int nbIterationPerFrame = 50;
    int nbBeforeFramechgt = nbIterationPerFrame;
    //private boolean characterNotMoving = true;

    private boolean characterAttacking = false; //boolean necessaire pour rendre l'animation d'attaque prioritaire

    //liste des coeurs drop par les monstres
    private static List<Hearth> hearthList = new ArrayList<>();

        //le sol
    public static Obstacle sol = new Obstacle(new HitBox(new Coordonnees(200,1064),1,1000000));

    public static List<Obstacle> obstacleTable = new ArrayList<>();
    private static List<Monster> monsterList = new ArrayList<>();
    private static List<Kunai> kunaiList = new ArrayList<>();
    private static List<Coffre> coffreTable = new ArrayList<>();

    public final static int TILES_DEFAULT_SIZE=32;
    public final static float SCALE=1.75f;
    public final static int TILES_IN_WIDTH = 60;
    public final static int TILES_IN_HEIGHT = 20;
    public final static int TILES_SIZE = (int) (TILES_DEFAULT_SIZE*SCALE);
    private static final LevelManager levelManager = new LevelManager();
    ;

    public Jeu(String source) {

        //cest la pour les sprites, remplacer Jeu.class par classedanslaquelletues.class
        BufferedReader helpReader;
        String fn = "Frames_perso";
        URL url = Jeu.class.getClassLoader().getResource(fn);
        assert url != null;
        beginPath = url.toString().substring(6)+"/";
        //************************* */
        
        movement = "character_idle";
        previousMovement = movement;
        numberOfMovement = 1;
        characterSkinPath = beginPath + movement + numberOfMovement + ".png"; // path premiere frame
        /*A = new ArrayList<Double>();
        n = 0;*/

        
        try {
            helpReader = new BufferedReader(new FileReader(source));
            String line;
            while ((line = helpReader.readLine()) != null) {
                System.out.println(line);
            }
            helpReader.close();
        } catch (IOException e) {
            System.out.println("Help not available");
        }

        //on remplit la table de directions du jeu
        directionJeu = new HashMap<>();
        directionJeu.put("Right", false);
        directionJeu.put("Left", false);
        directionJeu.put("Jump", false);
        directionJeu.put("Attack",false);
        
        
        //on genere la table des obstacles
        obstacleTable= levelManager.generateObstacleTable();
        obstacleTable.add(sol);




        /*obstacleTable.add(new Obstacle(new HitBox(new Coordonnees(300,550),32,128)));
        obstacleTable.add(new Obstacle(new HitBox(new Coordonnees(800, 625),150,50)));
        obstacleTable.add(new Obstacle(new HitBox(new Coordonnees(600, 662.5),75,50)));
        obstacleTable.add(new Obstacle(new HitBox(new Coordonnees(450, 400),32,128)));*/

        //on genere la table des coffres
        coffreTable = levelManager.generateCoffreTable();

        //on met des monstres, faut supp la pour table monstres
        /*monsterList.add(new Monster(new Coordonnees(1000, sol.getHitbox().getExtremites().get("HautGauche").getZ()-500), 1000, 30, 60, 1,5));
        monsterList.add(new Monster(new Coordonnees(500, sol.getHitbox().getExtremites().get("HautGauche").getZ()-500), 1000, 30, 60, 1,5));
        monsterList.add(new Monster(new Coordonnees(100, sol.getHitbox().getExtremites().get("HautGauche").getZ()-500), 1000, 30, 60, 1,5));
        monsterList.add(new Monster(new Coordonnees(320, sol.getHitbox().getExtremites().get("HautGauche").getZ()-500), 1000, 30, 60, 1,5));
        monsterList.add(new Bat(new Coordonnees(1500, sol.getHitbox().getExtremites().get("HautGauche").getZ()-500), 1, 3));
        monsterList.add(new Boss(new Coordonnees(3000, sol.getHitbox().getExtremites().get("HautGauche").getZ()-500), 500, 90, 180, 3, 50));*/
        //on charge le perso (a la fin du constructeur, cest important par rapport a obstacleTable, sinon y'a des pbs de "causalite")
        gameCharacterLoader = new CharacterLoader(characterSkinPath,new ShootingCharacter(new Coordonnees(xdebut, zdebut), 1500, 1,600000));
        gameCharacter = new ShootingCharacter(new Coordonnees(xdebut, zdebut), 1500, 1,600000);

        //on genere la table des monstres
        monsterList= levelManager.generateMonsterTable();
        monsterList.add(new Boss(new Coordonnees(5000, -1500), 500, 50, 100, 3, 50));
        //on remplit la map des frames
        Map<String,Integer> tempMap = gameCharacterLoader.getPathTable();

        tempMap.put(movement,4);

        tempMap.put("character_attack",3);
        tempMap.put("character_run", 4);
        tempMap.put("character_jump",1);
        tempMap.put("character_jump_L",1);
        tempMap.put("character_run_L",4);
        tempMap.put("character_attack_L",3);
        tempMap.put("character_idle_L",4);

        gameCharacterLoader.setPathTable(tempMap);
    }

    @Override
    public void evolve(HashMap<String,Boolean> command) {  // command est sous la forme map de Boolean qui represente les touches préssées. Voir Controller pour la compositions de cet list.
       
        previousMovement = movement;

        directionJeu.replace("Right", command.get("Right"));
        directionJeu.replace("Left", command.get("Left"));
        directionJeu.replace("Jump", command.get("Jump"));
        directionJeu.replace("Attack",command.get("Attack"));
        boolean Right = command.get("Right");
        boolean Left = command.get("Left");
        boolean Attack = command.get("Attack");


       
        //perso evolue dans le jeu (en actualisant ses coordonnees)
        gameCharacter.evolveCharacter();
        //monstres evoluent dans le jeu
        Monster.evolveAllMonsters(monsterList);
        //kunais evoluent dans le jeu
        Kunai.evolveAllKunais(kunaiList);
        //coeurs healent
        Hearth.evolveHearths();

        //animation du perso dans le jeu (definir la bonne frame a cet instant)
        animation(Attack, Right, Left);
        
    }

    @Override
    public boolean isFinished() {
        // le jeu n'est jamais fini
        return false;
    }

    private void animation(Boolean Attack,Boolean Right,Boolean Left){
        if (Attack && !characterAttacking) {
            movement = "character_attack";
            if (gameCharacter.getDirection() == -1)movement += "_L";
            characterAttacking = true;
        }

        if (!characterAttacking){ //animation d'attaque prioritaire
            if ( gameCharacter.getAlpha()==0) {
                movement = "character_jump";} // pour savoir si il jump ou non
            else{//savoir si il avance ou non
                if (Right && Left)movement = "character_idle";
                else if (Right || Left){
                    movement = "character_run";
                }
                else if (!Right && !Left){
                        
                    movement = "character_idle"; //ca changera quand j'aurai les nouvelles frames
                }
            }
            if (gameCharacter.getDirection() == -1)movement += "_L";//mvt gauche ou droit

        }

        
 
        //si on a change de mouvement, le jeu doit redemarrer a la premiere frame correspondante
        if ( !previousMovement.equals(movement)){numberOfMovement = 1;nbBeforeFramechgt = nbIterationPerFrame;}
        if (numberOfMovement == gameCharacterLoader.getPathTable().get(movement)){
            if (movement.equals("character_attack") || movement.equals("character_attack_L")){
                characterAttacking = false;
            }
        }
        if ((nbIterationPerFrame-nbBeforeFramechgt) == nbIterationPerFrame) { // timer pour changer de frame
            numberOfMovement = numberOfMovement%gameCharacterLoader.getPathTable().get(movement) + 1;
            nbBeforeFramechgt = nbIterationPerFrame;
        }
        else nbBeforeFramechgt--;
        
            
        //actualisation de l'image a afficher
        characterSkinPath = beginPath + movement + numberOfMovement + ".png";
        gameCharacterLoader.setSkinPath(characterSkinPath);
        gameCharacterLoader.refreshImage();
    }

    public static Map<String, Boolean> getDirectionJeu() {
        return directionJeu;
    }

    public static Obstacle getSol() {
        return sol;
    }

    public static List<Obstacle> getObstacleTable() {
        return obstacleTable;
    }
    public static List<Coffre> getCoffreTable() {
        return coffreTable;
    }

    public static Character getGameCharacter() {
        return gameCharacter;
    }

    public static List<Monster> getMonsterList() {
        return monsterList;
    }

    public static List<Kunai> getKunaiList() {
        return kunaiList;
    }

    public static void setKunaiList(List<Kunai> kunaiList) {
        Jeu.kunaiList = kunaiList;
    }

    public static LevelManager getLevelmanager() {
        return levelManager;
    }

    public static List<Hearth> getHearthList() {
        return hearthList;
    }

    
    
}