using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Redis.RedisEntities;
using Siger.Middlelayer.Redis.Utility;

namespace Siger.Middlelayer.Redis.Repositories
{
    public class MonitorTargetRepository : RedisRepositoryBase
    {
        private const string MonitorTargetKey = "targets";
        private readonly int _companyId;
        private readonly int _projectId;
        private readonly bool _dispose;

        public MonitorTargetRepository(int companyId, int projectId, bool dispose = true) : base(companyId, projectId)
        {
            _companyId = companyId;
            _projectId = projectId;
            _dispose = dispose;
        }

        public void Dispose()
        {
            Client?.Dispose();
        }

        private void Execute(string spindleName, string toolName, string programNo, int machineId)
        {
            try
            {
                //add monitortarget
                var monitorKey = ConditionHelper.GetMornotorKey(_companyId, _projectId, machineId);
                var monitor = Client.HGet(HashMonitorTarget, monitorKey);
                if (!string.IsNullOrWhiteSpace(monitor))
                {
                    var monitorTarget = JsonHelper.DeserializerJsonResult<Monitor>(monitor);
                    AddSpindle(monitorTarget, spindleName);
                    AddProgramName(monitorTarget, programNo);
                    AddToolName(monitorTarget, toolName);
                    Client.HSet(HashMonitorTarget, monitorKey, JsonHelper.SerializerToJsonString(monitorTarget));
                }
                else
                {
                    var monitorTarget = new Monitor();
                    AddSpindle(monitorTarget, spindleName);
                    AddProgramName(monitorTarget, programNo);
                    AddToolName(monitorTarget, toolName);
                    Client.HSet(HashMonitorTarget, monitorKey, JsonHelper.SerializerToJsonString(monitorTarget));
                }

                //add targets
                var target = Client.HGet(HashMonitorTarget, MonitorTargetKey);
                if (!string.IsNullOrWhiteSpace(target))
                {
                    var targets = JsonHelper.DeserializerJsonResult<List<MonitorTarget>>(target);
                    var currentTarget = targets.FirstOrDefault(q => q.CompanyId == _companyId && q.ProjectId == _projectId && q.MachineId == machineId);
                    if (currentTarget == null)
                    {
                        var monitorTarget = new MonitorTarget
                        {
                            ProjectId = _projectId,
                            CompanyId = _companyId,
                            MachineId = machineId
                        };
                        AddTargetSpindle(monitorTarget, spindleName);
                        AddTargetProgramName(monitorTarget, programNo);
                        AddTargetToolName(monitorTarget, toolName);
                        targets.Add(monitorTarget);
                        Client.HSet(HashMonitorTarget, MonitorTargetKey, JsonHelper.SerializerToJsonString(targets));
                    }
                    else
                    {
                        AddTargetSpindle(currentTarget, spindleName);
                        AddTargetProgramName(currentTarget, programNo);
                        AddTargetToolName(currentTarget, toolName);
                        var updatedTargets = targets.Where(q => q.CompanyId != _companyId || q.ProjectId != _projectId || q.MachineId != machineId).ToList();
                        updatedTargets.Add(currentTarget);
                        Client.HSet(HashMonitorTarget, MonitorTargetKey, JsonHelper.SerializerToJsonString(updatedTargets));
                    }
                }
                else
                {
                    var targets = new List<MonitorTarget>();
                    var monitorTarget = new MonitorTarget
                    {
                        ProjectId = _projectId,
                        CompanyId = _companyId,
                        MachineId = machineId
                    };
                    monitorTarget.Splindles.Add(spindleName);
                    monitorTarget.Tools.Add(toolName);
                    monitorTarget.ProgramNumbers.Add(programNo);
                    targets.Add(monitorTarget);
                    Client.HSet(HashMonitorTarget, MonitorTargetKey, JsonHelper.SerializerToJsonString(targets));
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                if (_dispose)
                {
                    Dispose();
                }
            }
        }

        public void AddMonitorTarget(string spindleName, string toolName, string programNo, int machineId)
        {
             Execute(spindleName, toolName, programNo, machineId);
        }

        public async Task AddMonitorTargetAsync(string spindleName, string toolName, string programNo, int machineId)
        {
           await Task.Run(() => { Execute(spindleName, toolName, programNo, machineId); });
        }

        private static void AddSpindle(Monitor monitorTarget, string spindleName)
        {
            if (!monitorTarget.Splindles.Contains(spindleName))
            {
                monitorTarget.Splindles.Add(spindleName);
            }
        }

        private static void AddToolName(Monitor monitorTarget, string toolName)
        {
            if (!monitorTarget.Tools.Contains(toolName))
            {
                monitorTarget.Tools.Add(toolName);
            }
        }

        private static void AddProgramName(Monitor monitorTarget, string programName)
        {
            if (!monitorTarget.ProgramNumbers.Contains(programName))
            {
                monitorTarget.ProgramNumbers.Add(programName);
            }
        }

        private static void AddTargetSpindle(MonitorTarget monitorTarget, string spindleName)
        {
            if (!monitorTarget.Splindles.Contains(spindleName))
            {
                monitorTarget.Splindles.Add(spindleName);
            }
        }

        private static void AddTargetToolName(MonitorTarget monitorTarget, string toolName)
        {
            if (!monitorTarget.Tools.Contains(toolName))
            {
                monitorTarget.Tools.Add(toolName);
            }
        }

        private static void AddTargetProgramName(MonitorTarget monitorTarget, string programName)
        {
            if (!monitorTarget.ProgramNumbers.Contains(programName))
            {
                monitorTarget.ProgramNumbers.Add(programName);
            }
        }
    }
}
