package com.insa.app.server;

import com.google.gson.Gson;
import com.insa.app.Resources;
import com.insa.app.model.User;
import com.mashape.unirest.http.ObjectMapper;
import com.mashape.unirest.http.Unirest;
import ro.pippo.core.Application;
import ro.pippo.core.Pippo;
import ro.pippo.core.WebServer;
import ro.pippo.core.route.RouteContext;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ServerBackend extends Application implements Runnable {

    private ServerDatabase db;

    public ServerBackend() {
        db = new ServerDatabase();
        Unirest.setObjectMapper(new ObjectMapper() {
            private Gson gson = new Gson();
            public <T> T readValue(String s, Class<T> c) {
                try { return gson.fromJson(s, c); } catch(Exception e) { throw new RuntimeException(e); }
            }
            public String writeValue(Object o) {
                try{ return gson.toJson(o); } catch(Exception e) { throw new RuntimeException(e); }
            }
        });
    }

    @Override
    protected void onInit() {
        PUT("/user", routeContext -> handlePutUser(routeContext)); //return local user
        DELETE("/user", routeContext -> handleDeleteUser(routeContext));
        GET("/user", routeContext -> handleGetClients(routeContext));
        POST("/user/name", routeContext -> handleChangeUserName(routeContext));
    }

    @Override
    public void run() {
        Pippo pippo = new Pippo(this);
        WebServer server = pippo.getServer();
        server.getSettings().host("0.0.0.0").port(Resources.serverPort);
        pippo.start();

    }

    private void handleChangeUserName(RouteContext ctx) {
        User user = ctx.json().createEntityFromBody(User.class);
        ctx.send(200);
        for (User stored_user : db.getConnectedClients()) {
            if (stored_user.equals(user)) {
                stored_user.setName(user.getName());
            }
        }
    }

    private void handlePutUser(RouteContext ctx) {
        User user = ctx.json().createEntityFromBody(User.class);
        ctx.send(200);
        // Notify all users
        for (User client : db.getConnectedClients()) {
            try {
                Unirest.put("http://" + client.getIpAddress() + "/user/connect")
                    .header("Content-Type", "application/json")
                    .body(user)
                    .asString();
            }
            catch (Exception e) {
                Logger.getAnonymousLogger().log(Level.WARNING, "Can't reach" + client.getIpAddress());
            }
        }
        db.addClient(user);
    }

    private void handleDeleteUser(RouteContext ctx) {
        User user = ctx.json().createEntityFromBody(User.class);
        ctx.send(200);
        db.disconnectClient(user);
        // Notify all users
        for (User client : db.getConnectedClients()) {
            try {
                Unirest.delete("http://" + client.getIpAddress() + "/users")
                    .header("Content-Type", "application/json")
                    .body(user)
                    .asString();
            }
            catch (Exception e) {
                Logger.getAnonymousLogger().log(Level.WARNING, "Can't reach" + client.getIpAddress());
            }
        }
    }

    private void handleGetClients(RouteContext ctx) {
        List<User> clients = db.getConnectedClients();
        ctx.json().send(clients);
    }
}
