package jnet.client;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.function.Consumer;
import javax.swing.JOptionPane;
import jnet.client.gui.UIUpdater;
import jnet.client.network.NettyClient;
import jnet.lib.LogFile;
import jnet.lib.Message;
import jnet.lib.object.Event;
import jnet.lib.object.Map;
import jnet.lib.object.MapObject;
import jnet.lib.object.ObjectType;
import jnet.lib.object.OnlineClients;
import jnet.lib.object.ServerConfig;
import jnet.lib.object.SnmpProfile;
import jnet.lib.object.User;

public class ClientMessageParser {

    private static final java.util.Map<Integer, Consumer<Message>> handlers = new HashMap<>();

    static {
        handlers.put(Message.CLIENT_VERSION, ClientMessageParser::handleClientVersion);
        handlers.put(Message.UPDATE, ClientMessageParser::handleUpdate);
        handlers.put(Message.AUTH_REQUEST, ClientMessageParser::handleAuthRequest);
        handlers.put(Message.AUTH_SUCEFULL, ClientMessageParser::handleAuthSuccessful);
        handlers.put(Message.AUTH_FAIL, ClientMessageParser::handleAuthFail);
        handlers.put(Message.ONLINE_CLIENTS, ClientMessageParser::handleOnlineClients);
        handlers.put(Message.OBJECT_TYPE, ClientMessageParser::handleObjectType);
        handlers.put(Message.USER, ClientMessageParser::handleUser);
        handlers.put(Message.USER_INFO, ClientMessageParser::handleUserInfo);
        handlers.put(Message.MAP, ClientMessageParser::handleMap);
        handlers.put(Message.STATUS_UPDATE, ClientMessageParser::handleStatusUpdate);
        handlers.put(Message.SET_MAP_LOCK, ClientMessageParser::handleSetMapLock);
        handlers.put(Message.SNMP_PROFILE, ClientMessageParser::handleSnmpProfile);
        handlers.put(Message.EVENT_LIST, ClientMessageParser::handleEventList);
        handlers.put(Message.EVENT_NEW, ClientMessageParser::handleEventNew);
        handlers.put(Message.EVENT_UPDATE, ClientMessageParser::handleEventUpdate);
        handlers.put(Message.ADD_OBJECT, ClientMessageParser::handleAddObject);
        handlers.put(Message.REMOVE_OBJECT, ClientMessageParser::handleRemoveObject);
        handlers.put(Message.UPDATE_OBJECT, ClientMessageParser::handleUpdateObject);
        handlers.put(Message.MAP_REMOVE, ClientMessageParser::handleMapRemove);
        handlers.put(Message.USER_EDIT, ClientMessageParser::handleUserEdit);
        handlers.put(Message.DELETE_LOG, ClientMessageParser::handleDeleteLog);
        handlers.put(Message.SERVER_CONFIG, ClientMessageParser::handleServerConfig);
    }

    public static void parse(Message msg) {
        LogFile.printDebug("-> Message type: " + msg.getType());
        handlers.getOrDefault(msg.getType(), m -> LogFile.printErr("Neznámý typ zprávy")).accept(msg);
    }

    private static void handleClientVersion(Message msg) {
        NettyClient.send(Message.CLIENT_VERSION, Client.CLIENT_VERSION);
    }

    private static void handleUpdate(Message msg) {
        LogFile.printInfo("Received update request");
        // TODO: Dialogové okno s informací o aktualizaci a odpočtem k jejímu provedení
    }

    private static void handleAuthRequest(Message msg) {
        String[] userPass = {Client.config.getString("user"), Client.config.getString("password"), String.valueOf(OnlineClients.PLATFORM_PC)};
        NettyClient.send(Message.AUTH, userPass);
    }

    private static void handleAuthSuccessful(Message msg) {
        LogFile.printInfo("Log in to server");
        Client.setConnected();
    }

    private static void handleAuthFail(Message msg) {
        LogFile.printInfo("Authorization failed on server");
        JOptionPane.showMessageDialog(null, "Chybné přihlašovací údaje!", "Chyba", JOptionPane.ERROR_MESSAGE);

    }

    private static void handleOnlineClients(Message msg) {
        Client.onlineClients = (ArrayList<OnlineClients>) msg.getMsg();
    }

    private static void handleObjectType(Message msg) {
        Client.objectType.add((ObjectType) msg.getMsg());
    }

    private static void handleUser(Message msg) {
        Client.users.add((User) msg.getMsg());
    }

    private static void handleUserInfo(Message msg) {
        Client.user = (User) msg.getMsg();
    }

    private static void handleMap(Message msg) {
        Client.maps.add((Map) (Map) msg.getMsg());
        // aktualizace UI
        UIUpdater.updateMapTree();
        UIUpdater.updateTray();
    }

    private static void handleStatusUpdate(Message msg) {
        int[] o = (int[]) msg.getMsg();
        int obj_id = o[0];
        int status = o[1];
        for (Map map : Client.maps) {
            for (MapObject mapObject : map.getObjects()) {
                if (mapObject.getId() == obj_id) {
                    mapObject.setStatus(status);
                    // aktualizace UI
                    UIUpdater.updateMapTree();
                    UIUpdater.updateTray();
                    UIUpdater.updateMapView();
                    break;
                }
            }
        }
        SoundManager.changeStatus(status);
    }

    private static void handleSetMapLock(Message msg) {
        int[] data_lock = (int[]) msg.getMsg();
        for (Map map : Client.maps) {
            if (map.getId() == data_lock[0]) {
                map.setLock((data_lock[1] == 1));
                break;
            }
        }
    }

    private static void handleSnmpProfile(Message msg) {
        Client.snmpProfile.add((SnmpProfile) msg.getMsg());
    }

    private static void handleEventList(Message msg) {
        Client.events = (ArrayList<Event>) msg.getMsg();
    }

    private static void handleEventNew(Message msg) {
        Client.events.add((Event) msg.getMsg());
    }

    private static void handleEventUpdate(Message msg) {
        Event event_update = (Event) msg.getMsg();
        for (int i = 0; i < Client.events.size(); i++) {
            if (event_update.getId() == Client.events.get(i).getId()) {
                Client.events.set(i, event_update);
                break;
            }
        }
    }

    private static void handleAddObject(Message msg) {
        MapObject mo = (MapObject) msg.getMsg();
        for (Map map : Client.maps) {
            if (map.getId() == mo.getMap()) {
                map.getObjects().add(mo);
                UIUpdater.updateMapView();
                break;
            }
        }
    }

    private static void handleRemoveObject(Message msg) {
        int objId = (int) msg.getMsg();
        for (Map map : Client.maps) {
            for (MapObject object : map.getObjects()) {
                if (object.getId() == objId) {
                    map.getObjects().remove(object);
                }
            }
        }
        // aktualizace UI
        UIUpdater.updateMapTree();
        UIUpdater.updateTray();
    }

    private static void handleUpdateObject(Message msg) {
        MapObject mo = (MapObject) msg.getMsg();
        for (Map map : Client.maps) {
            for (int i = 0; i < map.getObjects().size(); i++) {
                if (map.getObjects().get(i).getId() == mo.getId()) {
                    map.getObjects().set(i, mo);
                    UIUpdater.updateMapView();
                    break;
                }
            }
        }

    }

    private static void handleMapRemove(Message msg) {
        int mapId = (int) msg.getMsg();
        Client.maps.removeIf(map -> map.getId() == mapId);

    }

    private static void handleUserEdit(Message msg) {
        User ue = (User) msg.getMsg();
        Client.users.removeIf(user -> user.getId() == ue.getId());
    }

    private static void handleDeleteLog(Message msg) {
        int objId = (int) msg.getMsg();
        Client.events.removeIf(event -> event.getObject() == objId);
    }

    private static void handleServerConfig(Message msg) {
        Client.serverConfig = (ServerConfig) msg.getMsg();
    }

}
