using System.Text;
using M2Mqtt;
using M2Mqtt.Messages;
using System.Text.Json;

namespace RaspiControl {
    class Programm {
        private static MqttClient client;

        static void Main(string[] args) {
            try {
                client = new MqttClient("localhost");
                client.MqttMsgPublishReceived += Client_MqttMsgPublishReceived;
                string clientId = Guid.NewGuid().ToString();
                client.Connect(clientId);
                client.Subscribe(new string[] { MqttConstants.DEVICE_STATUS_APP_TOPIC }, new byte[] { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE });
                Joystick joystick = new Joystick();
                joystick.JoystickChanged += Joystick_JoystickChanged;

            } catch (Exception ex) {
                Console.WriteLine(ex.Message);
            }
        }

        private static void Joystick_JoystickChanged(object sender, JoystickEventArgs e) {
            switch (e.Button) {
                case JoystickButton.None:
                    break;
                case JoystickButton.Left:
                    client.Publish(MqttConstants.MOBILE_NAV_TURN_TOPIC, Encoding.UTF8.GetBytes($"{NavigationConstants.TURN_ANGLE_LEFT}"), MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE, false);
                    break;
                case JoystickButton.Right:
                    client.Publish(MqttConstants.MOBILE_NAV_TURN_TOPIC, Encoding.UTF8.GetBytes($"{NavigationConstants.TURN_ANGLE_RIGHT}"), MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE, false);
                    break;
                case JoystickButton.Up:
                    client.Publish(MqttConstants.MOBILE_NAV_MOVE_TOPIC, Encoding.UTF8.GetBytes($"{NavigationConstants.SPEED_FORWARD}"), MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE, false);
                    break;
                case JoystickButton.Down:
                    client.Publish(MqttConstants.MOBILE_NAV_MOVE_TOPIC, Encoding.UTF8.GetBytes($"{NavigationConstants.SPEED_BACKWARD}"), MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE, false);
                    break;
                case JoystickButton.Center:
                    client.Publish(MqttConstants.MOBILE_NAV_STOP_TOPIC, Encoding.UTF8.GetBytes($"{NavigationConstants.STOP}"), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);
                    break;
            }
        }

        private static void PublishSplitFlapDisplay(string message) {
            string payload = JsonSerializer.Serialize<Dictionary<string, string>>(new Dictionary<string, string>() { { "message", message } });
            client.Publish(MqttConstants.SPLITFLAP_DISPLAY_TOPIC, Encoding.UTF8.GetBytes(payload),MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE,false);
        }
        private static void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e) {
            string deviceId = "";
            Dictionary<string, object> data;
            if (e.Topic.StartsWith(string.Join('/',MqttConstants.DEVICE_STATUS_APP_TOPIC.Split('/').Take(2)))) {
                if(e.Topic.EndsWith(MqttConstants.DEVICE_STATUS_APP_TOPIC.Split('/').Last())) {
                    deviceId = deviceIdFromStatusTopic(e.Topic);
                    if(deviceId == "mobile") {
                            try {
                                data = getValueFromTopic(Encoding.UTF8.GetString(e.Message));
                                object value;
                                data.TryGetValue("state", out value);
                                if (value != null) {
                                    APP_STATE appState = (APP_STATE)Convert.ToUInt16(value.ToString());
                                    switch (appState) {
                                        case APP_STATE.STARTUP:
                                        Console.WriteLine("Startup");
                                        client.Publish(MqttConstants.SPLITFLAP_INIT_TOPIC, new byte[] { }, MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE, false);
                                        break;
                                        case APP_STATE.INIT:
                                        Console.WriteLine("Init");
                                        PublishSplitFlapDisplay("INIT");
                                            break;
                                        case APP_STATE.CALIBRATE:
                                            break;
                                        case APP_STATE.FOLLOW_LINE:
                                        Console.WriteLine("Follow line");
                                        PublishSplitFlapDisplay("AUTO");
                                            break;
                                        case APP_STATE.IDLE:
                                            break;
                                        case APP_STATE.FINAL:
                                            break;
                                        case APP_STATE.READY:
                                        Console.WriteLine("ready");
                                        PublishSplitFlapDisplay("REDY");
                                            break;
                                        default:
                                            throw new ArgumentException();
                                    }
                                }
                            } catch(Exception) {
                                Console.WriteLine($"Invalid payload received: {Encoding.UTF8.GetString(e.Message)}");
                            }
                            
                            
                        } 
                    else {
                            Console.WriteLine($"on topic: {e.Topic} no key with state found! | {Encoding.UTF8.GetString(e.Message)}");
                    }
                }
            }
        }

        private static string deviceIdFromStatusTopic(string statusTopic) {
            string[] topic = statusTopic.Split('/');
            return topic[topic.Length - 2];
        }
        private static Dictionary<string, object> getValueFromTopic(string topic) {
            return JsonSerializer.Deserialize<Dictionary<string, object>>(topic);
        }
    }
}