package com.uca;

import com.uca.dao._Initializer;
import com.uca.core.UserCore;
import com.uca.core.PokemonCore;
import com.uca.core.ExchangeCore;
import com.uca.gui.*;



import static spark.Spark.*;
import spark.Request;
import spark.Response;
import spark.Session;

public class StartServer {

    private enum Login{
        ERROR(0),
        SUCCESS(1),
        FIRSTCO(2),
        INCORRECT(3);

        private int value;

        Login(int value) 
        {
            this.value = value;
        }

        public int getValue() 
        {
            return value;
        }
    }

    private enum InitiateExchange{
        ERROR(0),
        SUCCESS(1),
        INCORRECTPKM(2),
        INCORRECTLVL(3);

        private int value;

        InitiateExchange(int value) 
        {
            this.value = value;
        }

        public int getValue() 
        {
            return value;
        }
    }

    private enum Base{
        ERROR(0),
        SUCCESS(1),
        FAILURE(2);

        private int value;

        Base(int value) 
        {
            this.value = value;
        }

        public int getValue() 
        {
            return value;
        }
    }

    public static void main(String[] args) {
        //Configure Spark
        staticFiles.location("/static/");
        port(8081);



        _Initializer.Init();


        //profile utilisateur
        get("/user/:id", (req, res) -> {
            int result = UserCore.userExist(Integer.parseInt(req.params(":id")));
            Base loginStatus = Base.values()[result];
            switch(loginStatus)
            {
                case ERROR:
                    halt(500, "Server error, please try again later");
                    break;
                case SUCCESS:
                    if(req.session().attribute("user_id") != null &&  req.session().attribute("user_id").equals(Integer.parseInt(req.params(":id"))))
                        return UserGUI.getMyProfileById(Integer.parseInt(req.params(":id")));
                    else
                        return UserGUI.getUserById(Integer.parseInt(req.params(":id")));
                case FAILURE:
                    halt(404, "This user dosen't exist");
                    break;
            }
            return null;
        });

        //Racine
        get("/", (req,res) ->{
            if(req.session().attribute("user_id") != null)
            {
                int userId = req.session().attribute("user_id");
                res.redirect("/user/"+ String.valueOf(userId));
            }
            else
            {
                String str = new UtilGUI().frontPage();
                if(str == null)
                {
                    res.status(404);
                    res.body("html not found");
                    return null;
                }
                res.type("text/html");
                res.status(200);
                return str;
            }
            return null;                
        });

        //Redirige vers le profil de l'utilisateur connecté (peut etre appelé depuis un form)
        get("/userRedirect", (req,res) ->{
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            int userId = req.session().attribute("user_id");
            res.redirect("/user/"+ String.valueOf(userId));
            return null;
        });

        //Pour première connexion journalière, donne un nouveau pokemon a un utilisateur
        get("/user/:id/newPkm", (req, resp) ->{
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            int userId = req.session().attribute("user_id");
            int id = Integer.parseInt(req.params(":id"));
            if(req.session().attribute("user_id") != null && userId != id)
            {
                halt(401, "You are not welcome here");
            }
            //On utilise un cookie, c'est pas très propre
            if(req.session().attribute("firstco") != null && Boolean.parseBoolean(req.session().attribute("firstco")))
            {
                req.session().attribute("firstco","false");
                int result = UserCore.userExist(Integer.parseInt(req.params(":id")));
                Base loginStatus = Base.values()[result];
                switch(loginStatus)
                {
                    case ERROR:
                        halt(500, "Server error, please try again later");
                        break;
                    case SUCCESS:
                        return PokemonGUI.getNewPokemon(req.session().attribute("user_id"));
                    case FAILURE:
                        halt(404, "This user dosen't exist");
                        break;
                }
            }
            else
            {
                halt(401, "You are not welcome here");
            }
            return null;
        });

        //Renvoie les utilisateur ayant un pseudo ou login avec search
        get("/userSearch", (req,res) -> {
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            if(req.queryParams("search") == null)
            {
                halt(422, "You took a wrong turn");
            }
            if(req.queryParams("search").isEmpty())
            {
                halt(422, "Please enter a user id or pseudo");
            }
            return UserGUI.searchUser(req.queryParams("search"));
        }); 

        //Selectionne un pokemon lors de la réponse a un échange indéfini
        get("/exchange/:id/selectPokemon" , (req,resp) -> {
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            if(req.queryParams("pkmId") == null || req.queryParams("pkmLvl") == null || req.queryParams("pkmShiny") == null)
            {
                halt(412, "We couln't process");
            }
            //On ne vérifie pas si l'utilisateur a l'autorisation, donc un utilisateur peut échanger avec lui meme
            int result = ExchangeCore.exchangeExist(Integer.parseInt(req.params(":id")));
            Base loginStatus = Base.values()[result];
            int userId = req.session().attribute("user_id");
            switch(loginStatus)
            {
                case ERROR:
                    halt(500, "Server error, please try again later");
                    break;
                case SUCCESS:
                    return PokemonGUI.getPokemonForExchange(Integer.parseInt(req.params("id")),userId, Integer.parseInt(req.queryParams("pkmId")), Integer.parseInt(req.queryParams("pkmLvl")), Boolean.parseBoolean(req.queryParams("pkmShiny")));
                case FAILURE:
                    halt(404, "This page dosen't exist");
                    break;
            }
            return null;
        });

        //Permet de choisir un pokemon a échangé pour un échange défini
        get("/user/:userid/pokemon/:pkmid/exchange/choosePkm", (req,resp) -> {
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            int userId = req.session().attribute("user_id");
            int id = Integer.parseInt(req.params(":userid"));
            if(req.session().attribute("user_id") != null && userId != id)
            {
                halt(401, "You are not welcome here");
            }
            int result = UserCore.userExist(Integer.parseInt(req.params(":userid")));
            Base loginStatus = Base.values()[result];
            switch(loginStatus)
            {
                case ERROR:
                    halt(500, "Server error, please try again later");
                    break;
                case SUCCESS:
                    {
                        if(PokemonCore.isPokemonOwnedByUser(id, Integer.parseInt(req.params(":pkmid"))))
                            return PokemonGUI.getPokemonForNewExchangeOffer( id,userId, Integer.parseInt(req.params(":pkmid")));
                        else
                            halt(404, "This page dosen't exist");
                    }
                case FAILURE:
                    halt(404, "This page dosen't exist");
                    break;
            }
            return null;
        });

        //Creer un échange défini
        get("/user/:userid/pokemon/:pkmid/exchange", (req,resp) -> {
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            int userId = req.session().attribute("user_id");
            int id = Integer.parseInt(req.params(":userid"));
            if(userId == id)
                return ExchangeGUI.myNewExchange(userId , Integer.parseInt(req.params("pkmid")));
            else
                return ExchangeGUI.newExchange(id, Integer.parseInt(req.params("pkmid")), userId, 0);
        });

        //Affiche l'offre d'échange après le choix d'un pokemon lors d'un échange indéfini
        post("/user/:userid/pokemon/:pkmid/exchange/selected/:pkmid2", (req,resp) -> {
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            int userId = req.session().attribute("user_id");

            return ExchangeGUI.newExchange(Integer.parseInt(req.params("userid")), Integer.parseInt(req.params("pkmid")), userId, Integer.parseInt(req.params("pkmid2")));
        });

        //Valide un échnage indéfini
        post("/user/:userid/pokemon/:pkmid/exchange/valided/:pkmid2", (req,resp) -> {
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            int userId = req.session().attribute("user_id");
            

            int result = ExchangeCore.createNewExchange(userId, Integer.parseInt(req.params(":pkmid2")), Integer.parseInt(req.params(":userid")), Integer.parseInt(req.params(":pkmid")));

            InitiateExchange loginStatus = InitiateExchange.values()[result];
            switch(loginStatus)
            {
            case ERROR:
                halt(500, "Server error, please try again later");
                break;
            case SUCCESS:
                userId = req.session().attribute("user_id");
                //On devrait renvoiyer un 200 mais il est overwriten par le redirect
                resp.redirect("/user/"+ String.valueOf(userId));
                break;
            case INCORRECTPKM:
                halt(422, "This pokemon doesn't exist");
                break;
            case INCORRECTLVL:
                halt(422, "Non valid level");
                break;
            }

            return null;
        });

        //Permet de creer un nouvel échange indéfini
        post("/user/:id/exchangeOut/new", (req,resp) -> {
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            if(req.queryParams("dataId") == null)
            {
                halt(422, "Please select a pokemon to exchange");
            }
            int userId = req.session().attribute("user_id");
            int id = Integer.parseInt(req.params(":id"));
            if(req.session().attribute("user_id") != null && userId != id)
            {
                halt(401, "You are not welcome here");
            }
            if((req.queryParams("anyPkm") == null && req.queryParams("pkmName").isEmpty()) || (req.queryParams("anyLvl") == null && req.queryParams("pkmLvl").isEmpty()))
            {
                halt(422, "Please enter information about the pokemon you want");
            }
            String pkmName = "";
            if(!req.queryParams("pkmName").isEmpty())
                pkmName = req.queryParams("pkmName");

            int pkmLvl = 0;
            if(!req.queryParams("pkmLvl").isEmpty())
                pkmLvl = Integer.parseInt(req.queryParams("pkmLvl"));

            Boolean pkmShiny = req.queryParams("pkmShiny") == null;



            int result = ExchangeCore.createNewExchange(id, Integer.parseInt(req.queryParams("dataId")), pkmName, pkmLvl, pkmShiny);
            InitiateExchange loginStatus = InitiateExchange.values()[result];
            switch(loginStatus)
            {
            case ERROR:
                halt(500, "Server error, please try again later");
                break;
            case SUCCESS:
                userId = req.session().attribute("user_id");
                resp.redirect("/user/"+ String.valueOf(userId));
                break;
            case INCORRECTPKM:
                halt(422, "This pokemon doesn't exist");
                break;
            case INCORRECTLVL:
                halt(422, "Non valid level");
                break;
            }

            return null;
        });

        //Affiche l'échange cible
        get("/exchange/:id" , (req,resp) -> {
            return ExchangeGUI.getExchangeById(Integer.parseInt(req.params(":id")));
        });

        //Affiche les échange sortant d'un utilisateur
        get("/user/:id/exchangeOut" , (req,res) -> {
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            int userId = req.session().attribute("user_id");
            int id = Integer.parseInt(req.params(":id"));
            return ExchangeGUI.exchangeOut(id, userId == id);
        });

        //Affiche les échange entrant d'un utilisateur
        get("/user/:id/exchangeIn" , (req,res) -> {
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            int userId = req.session().attribute("user_id");
            int id = Integer.parseInt(req.params(":id"));
            if(req.session().attribute("user_id") != null && userId != id)
            {
                halt(401, "You are not welcome here");
            }
            return ExchangeGUI.exchangeIn(id);
        });

        //Affiche l'offre d'échange avant de la validé
        post("/exchange/:id/offer", (req,resp) -> {
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            return ExchangeGUI.getExchangeOffer(Integer.parseInt(req.params(":id")),Integer.parseInt(req.queryParams("dataId")));
        });

        //Accepte un échange
        post("/exchange/:id/accepted", (req,res)->{
            if(req.queryParams("dataId") == null)
            {
                Boolean success = ExchangeCore.doExchange(Integer.parseInt(req.params(":id")));
                if(success)
                {
                    res.redirect("/userRedirect");
                }
                else
                    halt(500, "The exchange failed");
            }
            else
            {
                int userId = req.session().attribute("user_id");
                Boolean success = ExchangeCore.doExchange(Integer.parseInt(req.params(":id")), Integer.parseInt(req.queryParams("dataId")), userId );

                if(success)
                {
                    res.redirect("/userRedirect");
                }
                else
                    halt(500, "The exchange failed");
            }
            return null;
        });

        //Refuse un échange
        post("/exchange/:id/refused" , (req,res) ->{
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            Boolean success = ExchangeCore.refuseExchange(Integer.parseInt(req.params(":id")));
            if(success)
            {
                res.redirect("/userRedirect");
            }
            else
                halt(500, "An error occured");
            return null;
        });

        //Annule un échange
        post("/exchange/:id/canceled" , (req,res) ->{
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            Boolean success = ExchangeCore.refuseExchange(Integer.parseInt(req.params(":id")));
            if(success)
            {
                res.redirect("/userRedirect");
            }
            else
                halt(500, "An error occured");
            return null;
        });

        //Inscription
        post("/signup", (req,resp) ->{
            if(req.queryParams("pseudo").isEmpty() && req.queryParams("userpwd").isEmpty() && req.queryParams("usermail").isEmpty())
            {
                halt(422, "Please enter information");
            }
            if(UserCore.userEmailExist(req.queryParams("usermail")))
            {
                halt(422, "This mail is already registered");
            } 
            else
            {
                if(UserCore.createUser(req.queryParams("pseudo"), req.queryParams("userpwd"), req.queryParams("usermail")) == null)
                    halt(500,"An error occured");
                else
                {
                    resp.status(201);
                    resp.redirect("/");
                }
            }
            return null;
        });

        //Connexion
        post("/login", (req,resp) ->{
            int result = UserCore.login(req.queryParams("userpwd"),req.queryParams("usermail"));
            Login loginStatus = Login.values()[result];
            int userId;
            switch(loginStatus)
            {
            case ERROR:
                halt(500, "Server error, please try again later");
                break;
            case SUCCESS:
                userId = UserCore.getUserIdByMail(req.queryParams("usermail"));
                req.session().attribute("user_id", userId);
                resp.redirect("/user/"+ String.valueOf(userId));
                break;
            case FIRSTCO:
                userId = UserCore.getUserIdByMail(req.queryParams("usermail"));
                req.session().attribute("user_id", userId);
                req.session().attribute("firstco", "true");
                resp.redirect("/user/"+ String.valueOf(userId)+"/newPkm");
            case INCORRECT:
                halt(422, "Incorrects informations");
                break;
            }
            return null;
        });

        //Fait monter un pokemon de niveau
        post("/lvlup", (req,resp) ->{
            if(req.session().attribute("user_id") == null)
            {
                halt(401, "You must login to do that");
            }
            int id = Integer.parseInt(req.queryParams("userid"));
            if(UserCore.lvlup(id))
            {
                int result = PokemonCore.lvlUpPokemonById(id);
                Base loginStatus = Base.values()[result];
                switch(loginStatus)
                {
                    case ERROR:
                        halt(500, "Server error, please try again later");
                        break;
                    case SUCCESS:
                        resp.redirect("/user/"+ String.valueOf(id));
                        break;
                    case FAILURE:
                        halt(202, "Already max level");
                        break;
                }
            }
            //resp.redirect("/user/"+ String.valueOf(req.session().attribute("user_id")));
            halt(202,"You don't have any lvl up left");
            return null;
        });
    }
}