package utb.fai;

import org.eclipse.paho.client.mqttv3.*;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;

/**
 * Jednoduchy univarzalni testovaci MQTT klient
 */
public class TestingMQTTClient implements MqttCallback {

    private MqttClient client;
    private String brokerUrl;
    private String clientId = "TesingClient";
    private final Set<String> subscribedTopics = new HashSet<>();

    public static void main(String[] args) {
        System.out.println(
                "Simple Testing MQTT client\n\nCreated by Martin Krcma\n------------------------------------------------------------------------");

        TestingMQTTClient interactiveClient = new TestingMQTTClient();
        interactiveClient.initBrokerUrl();
        interactiveClient.runConsole();
    }

    private void initBrokerUrl() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            System.out.print("Enter MQTT Broker URL (tcp://localhost:1883): ");
            this.brokerUrl = reader.readLine();
            if (this.brokerUrl.isEmpty()) {
                this.brokerUrl = "tcp://localhost:1883";
            }
            System.out.print("Enter MQTT client ID (TesingClient): ");
            this.clientId = reader.readLine();
            if (this.clientId.isEmpty()) {
                this.clientId = "TesingClient";
            }
            connect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void runConsole() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String line;
            System.out.println("Testing MQTT Client ready. Type '/help' for a list of commands.");

            while (!(line = reader.readLine()).equals("/quit")) {
                processCommand(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            disconnect();
        }
    }

    private void processCommand(String command) throws MqttException {
        String[] tokens = command.split(" ", 3);
        switch (tokens[0]) {
            case "/set-url":
                this.brokerUrl = tokens[1];
                System.out.println("Broker URL set to " + brokerUrl);
                break;
            case "/set-client-id":
                this.clientId = tokens[1];
                System.out.println("Client ID set to " + clientId);
                connect();
                break;
            case "/add-topic":
                subscribe(tokens[1]);
                break;
            case "/remove-topic":
                unsubscribe(tokens[1]);
                break;
            case "/list-topics":
                subscribedTopics.forEach(System.out::println);
                break;
            case "/send":
                sendMessage(tokens[1], tokens[2]);
                break;
            case "/help":
                printHelp();
                break;
            default:
                System.out.println("Unknown command. Type '/help' for a list of commands.");
                break;
        }
    }

    private void printHelp() {
        System.out.println("/set-url <broker-url> - Set the MQTT broker URL.");
        System.out.println("/set-client-id <client-id> - Set the client ID.");
        System.out.println("/add-topic <topic> - Subscribe to a topic.");
        System.out.println("/remove-topic <topic> - Unsubscribe from a topic.");
        System.out.println("/list-topics - List subscribed topics.");
        System.out.println("/send <topic> <message> - Send a message to a topic.");
        System.out.println("/help - Show this help message.");
        System.out.println("/quit - Quit the program.");
    }

    private void subscribe(String topic) throws MqttException {
        if (client == null || !client.isConnected()) {
            connect();
        }
        client.subscribe(topic);
        subscribedTopics.add(topic);
        System.out.println("Subscribed to topic: " + topic);
    }

    private void unsubscribe(String topic) throws MqttException {
        if (client != null && client.isConnected()) {
            if (subscribedTopics.remove(topic)) {
                client.unsubscribe(topic);
                System.out.println("Unsubscribed from topic: " + topic);
            } else {
                System.out.println("This topic is not subscribed!");  
            }
        }
    }

    private void sendMessage(String topic, String message) throws MqttException {
        if (client == null || !client.isConnected()) {
            connect();
        }
        MqttMessage mqttMessage = new MqttMessage(message.getBytes());
        mqttMessage.setQos(0);
        client.publish(topic, mqttMessage);
        System.out.println("Message sent to topic [" + topic + "]: " + message);
    }

    private void connect() {
        try {
            if (client != null) {
                System.out.println("Reconnecting ...");
                client.close();
            }
            client = new MqttClient(brokerUrl, clientId);
            MqttConnectOptions connOpts = new MqttConnectOptions();
            connOpts.setCleanSession(true);
            client.connect(connOpts);
            client.setCallback(this);
            System.out.println("Connected to broker: " + brokerUrl);
        } catch (MqttException ex) {
            System.out.println("FAILED TO CONNECT TO BROAKER!!");
            ex.printStackTrace();
            System.exit(-1);
        }
    }

    private void disconnect() {
        try {
            if (client != null && client.isConnected()) {
                client.disconnect();
                System.out.println("Disconnected from broker.");
            }
        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void connectionLost(Throwable cause) {
        System.out.println("Connection lost: " + cause.toString());
    }

    @Override
    public void messageArrived(String topic, MqttMessage message) {
        System.out.println("Message arrived. Topic: " + topic + " Message: " + new String(message.getPayload()));
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken token) {
        // .......
    }
}