using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CommonUsage.Protocols.VDA5050.Messages;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Protocol;
using MQTTnet.Server;
using Newtonsoft.Json;
using SimpleCore;
using SimpleCore.Library;

namespace StandardScene.CarTypes
{
    public class MasterMQTTCommunication
    {
        private IManagedMqttClient _client;
        private IManagedMqttClient _visualizationClient; // Separate client for visualization

        private const string OrderTopic = "vda5050/frldAGV/order";
        private const string StateTopic = "vda5050/frldAGV/state";

        private const string VisualizationTopic = "vda5050/frldAGV/visualization";
        private readonly string _connectionTopic = "vda5050/frldAGV/connection";
        private readonly string _instantAction = "vda5050/frldAGV/instantActions";
        private readonly string _factsheet = "vda5050/frldAGV/factsheet";
        private readonly string _carFields = "vda5050/frldAGV/carFields";



        //192.168.123.5
        public MasterMQTTCommunication()
        {
            // Initialize MQTT client and connect to broker
            var mqttFactory = new MqttFactory();
            _client = mqttFactory.CreateManagedMqttClient();

            var mqttClientOptions = new MqttClientOptionsBuilder()
                .WithTcpServer("localhost", 1883) // Connect to the local broker
                .WithCleanSession(true)
                .WithCleanStart(true)
                .Build();

            var managedOptions = new ManagedMqttClientOptionsBuilder()
                .WithClientOptions(mqttClientOptions)
                .WithMaxPendingMessages(20)
                .WithPendingMessagesOverflowStrategy(MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
                .Build();

            _client.StartAsync(managedOptions).GetAwaiter().GetResult();
            Console.WriteLine(" >>> Master-Control MQTT client connected to broker.");

            // Initialize separate client for visualization
            _visualizationClient = mqttFactory.CreateManagedMqttClient();
            var visualizationOptions = new MqttClientOptionsBuilder()
                .WithTcpServer("localhost", 1883)
                .WithClientId("Master-Visualization")
                .Build();

            var visualizationManagedOptions = new ManagedMqttClientOptionsBuilder()
                .WithClientOptions(visualizationOptions)
                .WithMaxPendingMessages(10) // Lower queue size for visualization
                .WithPendingMessagesOverflowStrategy(MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
                .Build();

            _visualizationClient.StartAsync(visualizationManagedOptions).GetAwaiter().GetResult();
            Console.WriteLine(" >>> Master-Control Visualization MQTT client initialized.");
            
        }

        public async Task RestartClient()
        {
            Console.WriteLine(" >>> Restarting MQTT client...");

            var stopTask = _client.StopAsync();
            if (await Task.WhenAny(stopTask, Task.Delay(5000)) == stopTask)
            {
                Console.WriteLine(" >>> MQTT client stopped successfully.");
            }
            else
            {
                Console.WriteLine(" >>> Timeout while stopping MQTT client.");
            }

            // Dispose and reinitialize the client
            //_client.Dispose();

            var mqttFactory = new MqttFactory();
            var newClient = mqttFactory.CreateManagedMqttClient();

            var mqttClientOptions = new MqttClientOptionsBuilder()
                .WithTcpServer("localhost", 1883)
                .Build();

            var managedOptions = new ManagedMqttClientOptionsBuilder()
                .WithClientOptions(mqttClientOptions)
                .Build();

            await newClient.StartAsync(managedOptions);
            Console.WriteLine(" >>> New MQTT client started.");
        }



        public void SubsribeToConnectionTopic()
        {
            _client.SubscribeAsync(_connectionTopic, MqttQualityOfServiceLevel.AtLeastOnce).GetAwaiter().GetResult();

            _client.ApplicationMessageReceivedAsync += async e =>
            {
                if (e.ApplicationMessage.Topic == _connectionTopic)
                {
                    Console.WriteLine($" >>>>>>> Subscribed to topic: {e.ApplicationMessage.Topic}");
                    var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
                    //LogMessage("RECEIVED", e.ApplicationMessage.Topic, payload);
                    var connectionStatusMessage = JsonConvert.DeserializeObject<connectionMessage>(payload);
                    var car = (VDA5050Car)SimpleLib.GetAllCars()
                        .FirstOrDefault(cc => cc is VDA5050Car vdaCar);
                    if (car == null)
                    {
                        Diagnosis.Post($"no car of serialNumber {connectionStatusMessage.serialNumber}");

                    }

                    car.ConnectionStatus = connectionStatusMessage.connectionState;
                    Console.WriteLine($">>>> Connection status: {connectionStatusMessage.connectionState}");
                }
            };
        }

        public void SubscribeToCarFields()
        {
            _client.SubscribeAsync(_carFields,MqttQualityOfServiceLevel.AtLeastOnce).GetAwaiter().GetResult();
            _client.ApplicationMessageReceivedAsync += async e =>
            {
                if (e.ApplicationMessage.Topic == _carFields)
                {
                    var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
                    Console.WriteLine(payload);
                    //TODO:处理字符串，拿想要的值
                }
            };
        }

        //public void SubsribeToFactSheetTopic()
        //{
        //    _client.SubscribeAsync(_factsheet, MqttQualityOfServiceLevel.AtMostOnce).GetAwaiter().GetResult();

        //    _client.ApplicationMessageReceivedAsync += async e =>
        //    {
        //        if (e.ApplicationMessage.Topic == _factsheet)
        //        {
        //            //Console.WriteLine($" >>>>>>> Subscribed to topic: {e.ApplicationMessage.Topic}");
        //            var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
        //            //LogMessage("RECEIVED FactSheet", e.ApplicationMessage.Topic, payload);
        //            // Console.WriteLine($">>>> Connection status: {connectionStatusMessage.connectionState}");
        //        }
        //    };
        //}

        public void SubscribeToVisualization()
        {
            _visualizationClient.SubscribeAsync(VisualizationTopic, MqttQualityOfServiceLevel.AtMostOnce).GetAwaiter().GetResult();
            Console.WriteLine($" >>> Subscribed to {VisualizationTopic}");

            _visualizationClient.ApplicationMessageReceivedAsync += async e =>
            {
                if(_visualizationClient.PendingApplicationMessagesCount > 5)
                {
                    Console.WriteLine($"[WARNING] Dropping old visualization message. Pending: {_visualizationClient.PendingApplicationMessagesCount}");
                    return; // Skip processing to catch up
                }
                if (e.ApplicationMessage.Topic == VisualizationTopic)
                {
                    var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
                    //Console.WriteLine($"[DEBUG] Received Visualization Message: {payload}");

                    var state = JsonConvert.DeserializeObject<visualizationMessage>(payload);
                    var car = (VDA5050Car)SimpleLib.GetAllCars()
                        .FirstOrDefault(cc => cc is VDA5050Car vdaCar);

                    if (car != null)
                    {
                        car.UpdatePosition(state);
                    }
                }
                await Task.CompletedTask;
            };
        }

        public void SubscribeToState()
        {
            _client.SubscribeAsync(StateTopic, MqttQualityOfServiceLevel.AtMostOnce).GetAwaiter().GetResult();
            Console.WriteLine($"Subscribed to topic: {StateTopic}");
            _client.ApplicationMessageReceivedAsync += async e =>
            {
                Console.WriteLine("e.ApplicationMessage.Topic: " + e.ApplicationMessage.Topic + "  StateTopic: " + StateTopic);
                if (e.ApplicationMessage.Topic == StateTopic)
                {
                    Console.WriteLine($" >>>>>>> Subscribed to topic: {e.ApplicationMessage.Topic}");
                    var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
                    //LogMessage("RECEIVED", e.ApplicationMessage.Topic, payload);
                    // Console.WriteLine($" >> Topic: [{e.ApplicationMessage.Topic}] -- {payload}");
                    var state = JsonConvert.DeserializeObject<stateMessage>(payload);
                    var car = (VDA5050Car)SimpleLib.GetAllCars()
                        .FirstOrDefault(cc => cc is VDA5050Car vdaCar);
                    if (car == null)
                    {
                        Diagnosis.Post($"no car of serialNumber {state.serialNumber}");

                    }
                    car.IsPaused = state.paused;
                    car.UpdateState(state);
                    //car.UpdatePosition(state);
                    //Console.WriteLine($">> Received message on topic '{StateTopic}': {payload}");
                    // onTopicReceived(state);
                }
                await Task.CompletedTask;
            };
        }

        //public void SubscribeToState()
        //{
        //    _client.SubscribeAsync(StateTopic, MqttQualityOfServiceLevel.AtMostOnce).GetAwaiter().GetResult();
        //    _client.ApplicationMessageReceivedAsync += async e =>
        //    {
        //        if (e.ApplicationMessage.Topic == StateTopic)
        //        {
        //            var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
        //            var state = JsonConvert.DeserializeObject<stateMessage>(payload);
        //            var car = (VDA5050Car)SimpleLib.GetAllCars().FirstOrDefault(cc => cc is VDA5050Car);
        //            if (car == null)
        //            {
        //                Diagnosis.Post($"no car of serialNumber {state.serialNumber}");
        //            }
        //            else
        //            {
        //                // Instead of calling UpdateState/UpdatePosition directly,
        //                // simply store the latest state message.
        //                car.SetLatestState(state);
        //            }
        //        }
        //        await Task.CompletedTask;
        //    };
        //}



        public async Task PublishTo(string order)
        {
            var message = new MqttApplicationMessageBuilder()
                .WithTopic(OrderTopic)
                .WithPayload(order)
                 .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
                .Build();
            //Console.WriteLine($"[MQTT-Master] Pending Messages before sending: {_client.PendingApplicationMessagesCount}");

            await _client.EnqueueAsync(message);
            //Console.WriteLine($"[MQTT-Master] Sent order message. Pending Messages after sending: {_client.PendingApplicationMessagesCount}");

            //LogMessage("Sent Order", OrderTopic, order);
        }

        public async Task PublishInstantActions(string actions)
        {
            var message = new MqttApplicationMessageBuilder()
                .WithTopic(_instantAction)
                .WithPayload(actions)
                .Build();

            await _client.EnqueueAsync(message);

        }

        public void LogMessage(string direction, string topic, string payload)
        {
            string formattedPayload = payload;

            // Try to parse the payload as JSON and pretty-print it
            try
            {
                var jsonObject = JsonConvert.DeserializeObject(payload);
                formattedPayload = JsonConvert.SerializeObject(jsonObject, Formatting.Indented);
            }
            catch (JsonReaderException)
            {
                // If the payload is not valid JSON, just leave it as is
                formattedPayload = payload;
            }

            Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] [{direction}] Topic: {topic}, Payload: {formattedPayload}");
        }
    }
}