package com.uca.dao;

import com.uca.entity.PokemonEntity;
import com.uca.util.JsonReader;


import java.sql.*;
import java.util.Date;
import java.util.ArrayList;
import java.util.Random;
import java.io.IOException;

import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONArray;



public class PokemonDAO extends _Generic<PokemonEntity>{

    //Récupère les info d'un pokemon sur le pokeapi avec un id
    public PokemonEntity getPokemonById(int id) throws JSONException, IOException
    {
        PokemonEntity entity = new PokemonEntity();
        JsonReader jsonRd = new JsonReader();
        JSONObject json = jsonRd.readJsonFromUrl("https://pokeapi.co/api/v2/pokemon/" + String.valueOf(id));
        entity.setId(id);
        entity.setName(json.getString("name"));
        entity.setDescription(getPokemonDescriptionById(id));

        JSONArray type = json.getJSONArray("types");
        for(int i = 0 ; i < type.length() ; i++)
        {
            entity.setType(i, type.getJSONObject(i).getJSONObject("type").getString("name"));
        }
        return entity;
    }

    //Verfifie si un pokemon exist sur le pokeapi
    public Boolean pokemonExist(String name) throws IOException, JSONException
    {
        Boolean exist  = null;
        JsonReader jsonRd = new JsonReader();
        JSONObject json = jsonRd.readJsonFromUrl("https://pokeapi.co/api/v2/pokemon/" + name);
        if(json == null)
            exist = false;
        else 
            exist = true;
        return exist;
    }

    //Verfifie si un pokemon exist sur le pokeapi
    public Boolean pokemonExist(int id) throws IOException, JSONException
    {
        Boolean exist  = null;
        JsonReader jsonRd = new JsonReader();
        JSONObject json = jsonRd.readJsonFromUrl("https://pokeapi.co/api/v2/pokemon/" + String.valueOf(id));
        if(json == null)
            exist = false;
        else 
            exist = true;
        return exist;
    }


    //Récupere le genre possible d'un pokemon sur le pokeapi puis tire au hasard et le renvoie
    public String getPokemonGenderById(int id) throws JSONException, IOException
    {
        String gender = "unknown";
        JsonReader jsonRd = new JsonReader();
        JSONObject json = jsonRd.readJsonFromUrl("https://pokeapi.co/api/v2/pokemon-species/" + String.valueOf(id));
        int genderRatio = json.getInt("gender_rate");
        switch(genderRatio)
        {
        case -1:
            return "genderless";
        case 0:
            return "male";
        case 1:
            return Math.random() < 0.125 ? "female" : "male";
        case 2:
            return Math.random() < 0.25 ? "female" : "male";
        case 6:
            return Math.random() < 0.75 ? "female" : "male";
        case 7:
            return Math.random() < 0.875 ? "female" : "male";
        case 8:
            return "female";
        default:
            return Math.random() < 0.5 ? "female" : "male";
        }
    }

    //Récupère l'id d'un pokemon avec son nom
    public int getPokemonIdByName(String name) throws IOException
    {
        JsonReader jsonRd = new JsonReader();
        JSONObject json = jsonRd.readJsonFromUrl("https://pokeapi.co/api/v2/pokemon/" + name);
        return json.getInt("id");
    }

    public ArrayList<PokemonEntity> getPokemonForExchange(int ownerId, PokemonEntity pkm) throws IOException
    {
        ArrayList<PokemonEntity> entities = new ArrayList<PokemonEntity>();
        try 
        {
            PokemonEntity entity;
            PreparedStatement preparedStatement;
            if(pkm.getId() != 0)
            {
                preparedStatement = this.connect.prepareStatement("SELECT * FROM own WHERE idOwner = (?) AND idpkm = (?) AND lvl >= (?);");
                preparedStatement.setInt(1, ownerId);
                preparedStatement.setInt(2, pkm.getId());
                preparedStatement.setInt(3, pkm.getLvl());
            }
            else 
            {
                preparedStatement = this.connect.prepareStatement("SELECT * FROM own WHERE idOwner = (?) AND lvl >= (?);");
                preparedStatement.setInt(1, ownerId);
                preparedStatement.setInt(2, pkm.getLvl());
            }
            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) 
            {
                if((pkm.getShiny() && resultSet.getBoolean("shiny")) || !pkm.getShiny()) 
                {                    
                    entity = getPokemonById(resultSet.getInt("idpkm"));
                    entity.setDescription(getPokemonDescriptionById(resultSet.getInt("idpkm")));
                    entity.setShiny(resultSet.getBoolean("shiny"));
                    entity.setGender(resultSet.getString("gender"));
                    entity.setLvl(resultSet.getInt("lvl"));
                    entity.setGettingDate(resultSet.getDate("getting_date"));
                    entity.setBaseOwner(resultSet.getInt("baseowner"));
                    entity.setDataId(resultSet.getInt("id"));
                    setPokemonSprite(entity);
                    entities.add(entity);
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }


        return entities;
    }

    //Récupère le nom d'un pokemon avec un id
    public String getPokemonNameById(int id) throws JSONException, IOException
    {
        JsonReader jsonRd = new JsonReader();        

        JSONObject json = jsonRd.readJsonFromUrl("https://pokeapi.co/api/v2/pokemon/" + String.valueOf(id));
        return json.getString("name");
    }

    //Tire aléatoirement un pokemon 
    public PokemonEntity getNewPokemon(int userId) throws IOException
    {
        Random rand = new Random();
        int pokeId = rand.nextInt((1008 - 1) + 1) + 1;
        PokemonEntity pkm = getPokemonById(pokeId);
        pkm.setGender(getPokemonGenderById(pokeId));
        pkm.setLvl(rand.nextInt((100 - 1) + 1) + 1);
        pkm.setShiny(Math.random() < 0.01);
        setPokemonSprite(pkm);
        try {            
            PreparedStatement preparedStatement = this.connect.prepareStatement("INSERT INTO own(idowner, idpkm, gender, shiny, lvl, baseowner, getting_date) VALUES(?, ? , ?, ?, ?, ?, ?);");
            java.util.Date date = new java.util.Date();

            preparedStatement.setInt(1, userId);
            preparedStatement.setInt(2, pokeId);
            preparedStatement.setString(3, pkm.getGender());
            preparedStatement.setBoolean(4, pkm.getShiny());
            preparedStatement.setInt(5, pkm.getLvl());
            preparedStatement.setInt(6, userId);
            preparedStatement.setDate(7, new java.sql.Date(date.getTime()));
            preparedStatement.executeUpdate();            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return pkm;
    }

    //Vérifie si un pokemon appartien bien a un utilisateur
    public Boolean isPokemonOwnedByUser(int userId, int pkmId) throws IOException
    {
        Boolean exist = null;
        try {

            PreparedStatement preparedStatement = this.connect.prepareStatement("SELECT * FROM own WHERE idOwner = ? AND id = ? ;");
            preparedStatement.setInt(1, userId);
            preparedStatement.setInt(2, pkmId);
            ResultSet resultSet = preparedStatement.executeQuery();
            exist =  resultSet.next();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return exist;
    }

    //Récupère la description d'un pokemon sur le pokeapi 
    public String getPokemonDescriptionById(int id) throws JSONException, IOException
    {
        JsonReader jsonRd = new JsonReader();
        JSONObject json = jsonRd.readJsonFromUrl("https://pokeapi.co/api/v2/pokemon-species/" + String.valueOf(id));
        String str = json.getJSONArray("flavor_text_entries").getJSONObject(0).getString("flavor_text");
        return str;
    }

    //Recupere un pokemon dans notre BDD
    public PokemonEntity getPokemonByDataId(int id) throws IOException
    {
        PokemonEntity pkm = null;
        try {        
            PreparedStatement preparedStatement = this.connect.prepareStatement("SELECT * from own WHERE id = (?);");
            preparedStatement.setInt(1, id);
            ResultSet resultSet = preparedStatement.executeQuery();
            if(resultSet.next())
            {
                pkm = getPokemonById(resultSet.getInt("idpkm"));
                pkm.setGender(resultSet.getString("gender"));
                pkm.setLvl(resultSet.getInt("lvl"));
                pkm.setShiny(resultSet.getBoolean("shiny"));
                pkm.setBaseOwner(resultSet.getInt("baseowner"));
                pkm.setDataId(id);
                setPokemonSprite(pkm);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return pkm;
    }

    //Récupère l'id de l'utilisateur ayant le pokemon donné
    public int getOwnerId(int pkmId) throws IOException
    {
        try {        
            PreparedStatement preparedStatement = this.connect.prepareStatement("SELECT idOwner from own WHERE id = (?);");
            preparedStatement.setInt(1, pkmId);
            ResultSet resultSet = preparedStatement.executeQuery();
            if(resultSet.next())
            {
                return resultSet.getInt("idOwner");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }

    //Ajoute un niveau au pokemon ciblé
    public int lvlUpPokemonById(int id)
    {
        try {        
            PreparedStatement preparedStatement = this.connect.prepareStatement("SELECT lvl from own WHERE id = (?);");
            preparedStatement.setInt(1, id);
            ResultSet resultSet = preparedStatement.executeQuery();
            if(resultSet.next())
            {
                if(resultSet.getInt("lvl") < 100)
                {
                    preparedStatement = this.connect.prepareStatement("UPDATE own SET lvl = lvl + 1 WHERE id = (?);");
                    preparedStatement.setInt(1, id);
                    preparedStatement.executeUpdate();
                    return 1;                  
                }
                else
                {
                    return 2;
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return 0;
    }

    //A l'aide d'info du pokeapi, met a jour le chemin du sprite d'un pokemon
    public static void setPokemonSprite(PokemonEntity pkm) throws JSONException, IOException
    {
        JsonReader jsonRd = new JsonReader();
        JSONObject json = jsonRd.readJsonFromUrl("https://pokeapi.co/api/v2/pokemon/" + String.valueOf(pkm.getId()));
        if(pkm.getShiny())
        {
            if(pkm.getGender() == "female" && json.getJSONObject("sprites").has("front_shiny_female") && !json.getJSONObject("sprites").isNull("front_shiny_female"))
            {
                pkm.setSprite("/pokemonSprite/shiny/female/"+String.valueOf(pkm.getId())+".png");
            }
            else
            {
                pkm.setSprite("/pokemonSprite/shiny/"+String.valueOf(pkm.getId())+".png");
            }
        }
        else
        {
            if(pkm.getGender() == "female" && json.getJSONObject("sprites").has("front_female") && !json.getJSONObject("sprites").isNull("front_female"))
            {
                pkm.setSprite("/pokemonSprite/female/"+String.valueOf(pkm.getId())+".png");           
            }
            else
            {
                pkm.setSprite("/pokemonSprite/"+String.valueOf(pkm.getId())+".png");
            }
        }
    }

    //Renvoie tout les pokemon d'un utilisateur
    public ArrayList<PokemonEntity> getPokemonByUser(int id) throws JSONException, IOException
    {
        ArrayList<PokemonEntity> entities = new ArrayList<PokemonEntity>();
        try 
        {
            PokemonEntity entity;
            PreparedStatement preparedStatement = this.connect.prepareStatement("SELECT * FROM own WHERE idOwner = (?);");
            preparedStatement.setString(1, String.valueOf(id));
            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) 
            {
                entity = getPokemonById(resultSet.getInt("idpkm"));
                entity.setDescription(getPokemonDescriptionById(resultSet.getInt("idpkm")));
                entity.setShiny(resultSet.getBoolean("shiny"));
                entity.setGender(resultSet.getString("gender"));
                entity.setLvl(resultSet.getInt("lvl"));
                entity.setGettingDate(resultSet.getDate("getting_date"));
                entity.setBaseOwner(resultSet.getInt("baseowner"));
                entity.setDataId(resultSet.getInt("id"));
                setPokemonSprite(entity);
                entities.add(entity);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return entities;
    }



    //Crée un pokemon, non implémenté
    @Override
    public PokemonEntity create(PokemonEntity pkm) 
    {
        //TODO !
        return null;
    }

    //Supprime un pokemon, non implémenté
    @Override
    public void delete(PokemonEntity pkm) 
    {
        //TODO !
    }
}
