using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using RobotClientWpf.Properties;
using RobotClientWpf.Utilities;
using RobotLib;

namespace RobotClientWpf
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private bool startupCanceled;
        private static Mutex? mutex;  // mutex with unique key
        private static readonly string mutexName = "00489402-435c-426e-9d11-9a2b839b39b6";  // random guid

        private static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
        private ChallengeFactory? challenge;
        private bool manualDisconnect;

        public MainWindow()
        {
            // Check if another instance is already running
            // There is already an instance running of this program
            if (Mutex.TryOpenExisting(mutexName, out mutex))
            {
                MessageBox.Show("Another instance of RobotClientWpf is already running!" + Environment.NewLine +
                 "You cannot open multiple instances.", "Already running", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                startupCanceled = true;
                Application.Current.Shutdown();
                return;
            }

            // new mutex and keep Alive
            mutex = new Mutex(false, mutexName);
            GC.KeepAlive(mutex);

            // start window
            InitializeComponent();
            this.challenge = new ChallengeFactory();
            // inform other views about challenge factory
            this.mainView.SetChallengeFactory(this.challenge);
            this.configView.SetChallengeFactory(this.challenge);
            // subscribe to events
            this.challenge.PublisherSubscriber.ConnectionStateChanged += PublisherSubscriber_ConnectionStateChanged;
        }

        private void PublisherSubscriber_ConnectionStateChanged(object? sender, bool e)
        {
            if(e == false)
            {
                if (manualDisconnect == true)
                {
                    manualDisconnect = false;
                    return;
                }
                this.DisplayBottomMessage(MessageSeverity.Error, "Connection to MQTT broker lost.");
                this.SetIpFieldsState(true, true, "Connect");
            }
        }

        private void BatteryChanged(object? sender, BatteryEventArgs e)
        {
            if (!Dispatcher.CheckAccess())
            {
                EventHandler<BatteryEventArgs> eventDelegate = BatteryChanged;
                Dispatcher.Invoke(eventDelegate, sender, e);
            }
            else
            {
                //labelBattery.Content = $"Battery: {e.Voltage} V";
            }
        }

        private void buttonBuzz_Click(object sender, RoutedEventArgs e)
        {
            //Robot.Instance.Buzzer.Beep(300, 500);
        }

        private void btnConnectDisconnect_Click(object sender, RoutedEventArgs e)
        {
            Task.Run(delegate ()
            {
                this.ClearBottomMessage();
                if (this.challenge.PublisherSubscriber.IsConnected)  // is connected => disconnect
                {
                    manualDisconnect = true;  // prevent wrong message
                    this.challenge.PublisherSubscriber.Disconnect();
                    this.DisplayBottomMessage(MessageSeverity.Success, "Disconnected from MQTT broker.");
                    this.SetIpFieldsState(true, true, "Connect");
                }
                else // is not yet connected => connect
                {
                    this.SetIpFieldsState(false, false, "Connecting...");
                    string ipAddress = UIAccessHelpers.GetTextboxText(tbIp);
                    if (IPAddress.TryParse(ipAddress, out _))
                    {
                        var connectionSuccess = this.challenge.PublisherSubscriber.Connect(ipAddress, "ADIS", "TEST");
                        if (connectionSuccess)
                        {
                            this.DisplayBottomMessage(MessageSeverity.Success, "Successfully connected to MQTT broker.");
                            this.SetIpFieldsState(false, true, "Disconnect");
                        }
                        else
                        {
                            this.DisplayBottomMessage(MessageSeverity.Error, $"Failed to connect to MQTT broker on address {ipAddress}.");
                            this.SetIpFieldsState(true, true, "Connect");
                        }
                    }
                    else
                    {
                        this.DisplayBottomMessage(MessageSeverity.Error, $"Unable to parse MQTT Broker IP address {ipAddress}.");
                        this.SetIpFieldsState(true, true, "Connect");
                    }
                }
            });
        }

        private void SetIpFieldsState(bool ipTextbox, bool connectDisconnectButton, string buttonText)
        {
            UIAccessHelpers.SetButtonState(btnConnectDisconnect, connectDisconnectButton);
            UIAccessHelpers.SetTextboxState(tbIp, ipTextbox);
            UIAccessHelpers.SetButtonContent(btnConnectDisconnect, buttonText);
        }

        public void DisplayBottomMessage(MessageSeverity severity, string message)
        {
            Brush col;
            switch (severity)
            {
                case MessageSeverity.Success:
                    col = Brushes.Green;
                    break;
                case MessageSeverity.Warning:
                    col = Brushes.Orange;
                    break;
                case MessageSeverity.Error:
                    col = Brushes.Red;
                    break;
                case MessageSeverity.Information:
                    col = Brushes.Blue;
                    break;
                case MessageSeverity.Unknown:
                default:
                    col = Brushes.DarkGray;
                    break;
            }

            UIAccessHelpers.SetTextblockTextAndForegroundColor(tbBottomMessage, message, col);
        }

        private void ClearBottomMessage()
        {
            this.DisplayBottomMessage(MessageSeverity.Information, "");
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (!startupCanceled)
            {
                // save settings
                Settings.Default.MqttBrokerIp = this.tbIp.Text;
                Settings.Default.Save();
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.tbIp.Text = Settings.Default.MqttBrokerIp;
        }
    }
}
