using Edge.Core.Processor;
using Edge.Core.Processor.Communicator;
using Edge.Core.Processor.Dispatcher.Attributes;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using GasConcentrations_Yt95h.MessageEntity;

namespace GasConcentrations_Yt95h
{
    [MetaPartsRequired(typeof(HalfDuplexActivePollingDeviceProcessor<,>))]
    [MetaPartsRequired(typeof(ComPortCommunicator<>))]
    [MetaPartsRequired(typeof(TcpClientCommunicator<>))]
    [MetaPartsDescriptor(
        "lang-zh-cn:元特气体浓度检测仪组lang-zh-tw:元特氣體濃度檢測儀組lang-en-us:GasConcentrationsGauges",
        "lang-zh-cn:用于驱动 Modbus 协议的气体浓度检测仪组lang-zh-tw:用於驅動 Modbus 協議的氣體濃度檢測儀組lang-en-us:Used for driven Gas Concentrations Gauge Group which use Modbus Protocol",
        new[] { "lang-zh-cn:传感器lang-zh-tw:傳感器lang-en-us:Sensor" })]
    public class SensorGroupHandler : TestableActivePollingDeviceHandler<byte[], MessageBase>
    {
        private IContext<byte[], MessageBase> context;
        private ILogger logger = null;
        private readonly List<SensorHandler> sensorHandlerList = new List<SensorHandler>();
        private int sensorHandlerIndex = 0;

        public List<SensorHandler> SensorHandlerList
        {
            get
            {
                return sensorHandlerList;
            }
        }

        public class SensorGroupConfiguration
        {
            public string DeviceAddressList { get; set; }
        }

        [ParamsJsonSchemas("GasConcentrationsGageGroupParamsJsonSchemas")]
        public SensorGroupHandler(SensorGroupConfiguration config, IServiceProvider services)
        {
            if (services != null)
            {
                var loggerFactory = services.GetRequiredService<ILoggerFactory>();
                logger = loggerFactory.CreateLogger("DynamicPrivate_GasConcentrations");
            }

            var deviceAddressArray = config.DeviceAddressList.Split(';', StringSplitOptions.RemoveEmptyEntries);
            logger.LogInformation($"SensorGroupHandler will create {deviceAddressArray.Length} sensor handlers for Gas Detector Group from local config");
            CreateSensorHandlers(deviceAddressArray);
        }

        private void CreateSensorHandlers(string[] deviceAddressArray)
        {
            foreach (string deviceAddress in deviceAddressArray)
            {
                var sensorHandler = new SensorHandler(Convert.ToByte(deviceAddress), logger);
                sensorHandlerList.Add(sensorHandler);
            }
        }

        public override void Init(IContext<byte[], MessageBase> context)
        {
            base.Init(context);
            this.context = context;

            context.Communicator.OnConnected += async (_, __) =>
            {
                logger.LogInformation($"SensorGroupHandler Connected to COM port");
                await Task.CompletedTask;
            };

            foreach (var handler in sensorHandlerList)
            {
                handler.Init(context);
            }

            var timeWindowWithActivePollingOutgoing = this.context.Outgoing as TimeWindowWithActivePollingOutgoing<byte[], MessageBase>;
            timeWindowWithActivePollingOutgoing.PollingMsgProducer = () =>
            {
                var sensorHandler = sensorHandlerList[sensorHandlerIndex++];
                sensorHandlerIndex = sensorHandlerIndex < sensorHandlerList.Count ? sensorHandlerIndex : 0;

                return sensorHandler.GetRequestMessage();
            };
        }

        public override Task Process(IContext<byte[], MessageBase> context)
        {
            this.context = context;
            var ph = this.sensorHandlerList.Find(p => (byte)(p.DeviceAddress) == context.Incoming.Message.Address);
            if (ph == null)
            {
                logger.LogError($"SensorGroupHandler does not contain sensorHandler with address: {context.Incoming.Message.Address.ToString("X2")}");
                return Task.CompletedTask;
            }

            return ph.Process(context);
        }
    }

    public enum DeviceState
    {
        /// <summary>
        /// first time eastalized the connection with FC, or disconnected from a established connection.
        /// </summary>
        Disconnected,

        Connected
    }
}