using System;
using System.Collections.Generic;
using System.Linq;
using System.Timers;
using Applications.UniversalApi_WebConsole_App.Hubs;
using Applications.UniversalApi_WebConsole_App.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json;

namespace Applications.UniversalApi_WebConsole_App.Controllers
{
    public class AlarmBarController : Controller
    {
        public static Dictionary<string, AlarmInformation> AlarmInformations= new Dictionary<string, AlarmInformation>();
        public static Dictionary<string, AlarmInformation> WarningInformations = new Dictionary<string, AlarmInformation>();
        public static Dictionary<string, AlarmInformation> Informations = new Dictionary<string, AlarmInformation>();

        public static IHubContext<AlarmHub> _hubContext;

        private static Timer AlarmTimer = new Timer(5000);

        private static int currentAlarmIndex = 0;
        private static int currentWarningIndex = 0;
        private static int currentInformationIndex = 0;

        public AlarmBarController(IHubContext<AlarmHub> hubContext)
        {
            if (AlarmBarController._hubContext == null)
            {
                AlarmBarController._hubContext = hubContext;
            }
            if (!AlarmTimer.Enabled)
            {
                AlarmTimer.Elapsed += new ElapsedEventHandler(AlarmTimer_Elapsed);
                AlarmTimer.Start();
            }
        }

        private static async void AlarmTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            RemoveOldAlarms();
            AlarmInformation tempAlarmInfo = null;
            int alarmInfoCount = 0;
            int warningInfoCount = 0;
            lock (AlarmInformations)
            {
                if ((AlarmInformations.Any() && !(AlarmInformations.Count > currentAlarmIndex)) || !AlarmInformations.Any())
                    currentAlarmIndex = 0;
                if (AlarmInformations.Count > 0 && AlarmInformations.Count > currentAlarmIndex && _hubContext != null)
                { 
                    tempAlarmInfo = AlarmInformations.Values.OrderByDescending(_ => _.OccurTime).ElementAt(currentAlarmIndex);
                    currentAlarmIndex++;
                }

                alarmInfoCount = AlarmInformations.Count;
            }

            lock (WarningInformations)
            {
                warningInfoCount = WarningInformations.Count;
            }

            if (tempAlarmInfo == null)
            {
                lock (WarningInformations)
                {
                    if ((WarningInformations.Any() && !(WarningInformations.Count > currentWarningIndex)) || !WarningInformations.Any())
                        currentWarningIndex = 0;
                    if (WarningInformations.Count > 0 && WarningInformations.Count > currentWarningIndex && _hubContext != null)
                    {
                        tempAlarmInfo = WarningInformations.Values.OrderByDescending(_=>_.OccurTime).ElementAt(currentWarningIndex);
                        currentWarningIndex++;
                    }
                }
            }

            if (tempAlarmInfo == null)
            {
                lock (Informations)
                {
                    if ((Informations.Any() && !(Informations.Count > currentInformationIndex)) || !Informations.Any())
                        currentInformationIndex = 0;
                    if (Informations.Count > 0 && Informations.Count > currentInformationIndex && _hubContext != null)
                    {
                        tempAlarmInfo = Informations.Values.OrderByDescending(_ => _.OccurTime).ElementAt(currentInformationIndex);
                        currentInformationIndex++;
                    }
                }
            }

            if (tempAlarmInfo != null)
                await _hubContext.Clients.All.SendAsync("AddMessage", "AlarmController", JsonConvert.SerializeObject(tempAlarmInfo), alarmInfoCount, warningInfoCount);
            else
            {
                tempAlarmInfo = new AlarmInformation() {Description = "",Severity = Severity.Information};
                if (_hubContext != null)
                    await _hubContext.Clients.All.SendAsync("AddMessage", "AlarmController",
                        JsonConvert.SerializeObject(tempAlarmInfo), alarmInfoCount, warningInfoCount);
            }
        }

        private static void RemoveOldAlarms()
        {
            var list = new List<string>();
            lock (AlarmInformations)
            {
                if (AlarmInformations.Count > 0)
                {
                    foreach (var alarm in AlarmInformations)
                    {
                        if ((DateTime.Now - alarm.Value.OccurTime).TotalMinutes > 2)
                        {
                            list.Add(alarm.Key);
                        }
                    }
                }
            }
            if(list.Count > 0)
            {
                lock (AlarmInformations)
                {
                    foreach (var key in list)
                    {
                        if (AlarmInformations.ContainsKey(key)) AlarmInformations.Remove(key);
                    }
                }
                list.Clear();
            }
            lock (WarningInformations)
            {
                if (WarningInformations.Count > 0)
                {
                    foreach (var warning in WarningInformations)
                    {
                        if ((DateTime.Now - warning.Value.OccurTime).TotalMinutes > 2)
                        {
                            list.Add(warning.Key);
                        }
                    }
                }
            }
            if (list.Count > 0)
            {
                lock (WarningInformations)
                {
                    foreach (var key in list)
                    {
                        if (WarningInformations.ContainsKey(key)) WarningInformations.Remove(key);
                    }
                }
                list.Clear();
            }
            lock (Informations)
            {
                if (Informations.Count > 0)
                {
                    foreach (var info in Informations)
                    {
                        if ((DateTime.Now - info.Value.OccurTime).TotalMinutes > 2)
                        {
                            list.Add(info.Key);
                        }
                    }
                }
            }
            if (list.Count > 0)
            {
                lock (Informations)
                {
                    foreach (var key in list)
                    {
                        if (Informations.ContainsKey(key)) Informations.Remove(key);
                    }
                }
                list.Clear();
            }
        }

        [HttpPost]
        //[HttpGet]
        public IActionResult AddInformation([FromBody]object information)
        {
            try
            {
                //var temp = new AlarmInformation() { Key = "2", Description = "testtest in controller", Severity = Severity.Alarm };
                //var tempStr = JsonConvert.SerializeObject(temp);
                var alarmInformation = JsonConvert.DeserializeObject<AlarmInformation>(information.ToString());
                //var notifyClients = false;
                if (alarmInformation.Severity == Severity.Alarm)
                {
                    lock (AlarmInformations)
                    {
                        if (!AlarmInformations.ContainsKey(alarmInformation.Key))
                        {
                            AlarmInformations.Add(alarmInformation.Key, alarmInformation);
                        }
                        else
                        {
                            AlarmInformations[alarmInformation.Key].OccurTime = alarmInformation.OccurTime;
                        }
                    }
                    return Ok();
                }

                if (alarmInformation.Severity == Severity.Warning)
                {
                    lock (WarningInformations)
                    {
                        if (!WarningInformations.ContainsKey(alarmInformation.Key))
                        {
                            WarningInformations.Add(alarmInformation.Key, alarmInformation);
                        }
                        else
                        {
                            WarningInformations[alarmInformation.Key].OccurTime = alarmInformation.OccurTime;
                        }
                    }
                    return Ok();
                }

                if (alarmInformation.Severity == Severity.Information)
                {
                    lock (Informations)
                    {
                        if (!Informations.ContainsKey(alarmInformation.Key))
                        {
                            Informations.Add(alarmInformation.Key, alarmInformation);
                        }
                        else
                        {
                            Informations[alarmInformation.Key].OccurTime = alarmInformation.OccurTime;
                        }
                    }
                    return Ok();
                }

                return BadRequest();
            }
            catch (Exception ex)
            {
                return BadRequest();
            }
        }

        [HttpPost]
        //public async Task<IActionResult> RemoveInformation(string key)
        public IActionResult RemoveInformation(string key)
        {
            try
            {
                //var notifyClients = false;
                lock (AlarmInformations)
                {
                    if (AlarmInformations.ContainsKey(key))
                    {
                        //notifyClients = true;
                        AlarmInformations.Remove(key);
                        if(!AlarmInformations.Any() || !(AlarmInformations.Values.Any(_ => _.Acked == false)))
                        {
                            _hubContext.Clients.All.SendAsync("MuteAlarmAduio");
                        }
                        return Ok();
                    }
                }

                lock (WarningInformations)
                {
                    if (WarningInformations.ContainsKey(key))
                    {
                        WarningInformations.Remove(key);
                        return Ok();
                    }
                }

                lock (Informations)
                {
                    if (Informations.ContainsKey(key))
                    {
                        Informations.Remove(key);
                        return Ok();
                    }
                }
                //if (notifyClients && this._hubContext != null)
                //{
                //    await _hubContext.Clients.All.SendAsync("Remove", key);
                //}
                return BadRequest();
            }
            catch(Exception ex)
            {
                return BadRequest();
            }
        }

        [HttpPost]
        public IActionResult AlarmAcked()
        {
            lock (AlarmInformations)
            {
                foreach (var info in AlarmInformations)
                {
                    info.Value.Acked = true;
                }
            }
            return Ok();
        }

        [HttpGet]
        public IActionResult GetAlarmInformation()
        {
            List<AlarmInformation> infos = new List<AlarmInformation>();
            lock (AlarmInformations)
            {
                if (AlarmInformations.Any())
                {
                    infos.AddRange(AlarmInformations.Values.OrderByDescending(_=>_.OccurTime));
                }
            }

            lock (WarningInformations)
            {
                if (WarningInformations.Any())
                {
                    infos.AddRange(WarningInformations.Values.OrderByDescending(_ => _.OccurTime));
                }
            }

            lock (Informations)
            {
                if (Informations.Any())
                {
                    infos.AddRange(Informations.Values.OrderByDescending(_ => _.OccurTime));
                }
            }
            return Ok(JsonConvert.SerializeObject(infos));
        }
    }
}