using System;
using System.IO;
using System.Threading.Tasks;
using Aitex.Common.Util;
using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.Event;
using Aitex.Core.RT.Log;
using Aitex.Core.RT.SCCore;
using Aitex.Core.Util;
using MECF.Framework.Common.Equipment;
using MECF.Framework.Common.Utilities;

namespace MECF.Framework.Common.DataCenter
{
	public class DiskManager
	{
        const long GB_TO_BYTES = 2 ^ 30;
		private PeriodicJob _threadMonitorDiskSpace;
        private bool _isDbFreeDiskSpaceLow = false;
        private long _dbFreeDiskSpaceAmount = 0;
        private readonly string _drvApp;
        private readonly string _drvDB;

        private readonly R_TRIG _rTrigAppFreeDiskSpaceLowWarn = new();
        private readonly R_TRIG _rTrigAppFreeDiskSpaceLowAlarm = new();
        private readonly R_TRIG _rTrigDBFreeDiskSpaceLowWarn = new();
        private readonly R_TRIG _rTrigDBFreeDiskSpaceLowAlarm = new();

		public bool IsEnableMonitorDiskSpaceFunc { get; set; }

		public DiskManager()
		{
			if (SC.ContainsItem("System.IsEnableMonitorDiskSpaceFunc"))
			{
				IsEnableMonitorDiskSpaceFunc = SC.GetValue<bool>("System.IsEnableMonitorDiskSpaceFunc");
			}

            var f = new FileInfo(PathManager.GetAppDir());
            _drvApp = Path.GetPathRoot(f.FullName);

            f = new FileInfo(PathManager.GetDBDictionary());
			_drvDB = Path.GetPathRoot(f.FullName);

            DATA.Subscribe($"{ModuleName.System}.{ModuleName.Diagnosis}.DiskMon.IsDBFreeDiskSpaceLow", () => _isDbFreeDiskSpaceLow);
            DATA.Subscribe($"{ModuleName.System}.{ModuleName.Diagnosis}.DiskMon.DBFreeDiskSpaceAmount", () => _dbFreeDiskSpaceAmount);
        }

		public void Run()
		{
			_threadMonitorDiskSpace = new PeriodicJob((int)TimeSpan.FromSeconds(30).TotalMilliseconds, MonitorDiskSpace, "MonitorDiskSpace Thread");
			Task.Delay(10000).ContinueWith(delegate
			{
				_threadMonitorDiskSpace.Start();
			});
		}

        private readonly R_TRIG _rTrigMonitorTimeOver = new();
		private bool MonitorDiskSpace()
		{
            try
            {
                PerformanceMonitor.MonitorRun(() =>
                    {
                        var freeDiskSpaceApp = 0L;
                        var totalDiskSpaceApp = 0L;
                        var freeDiskSpaceDB = 0L;
                        var totalDiskSpaceDB = 0L;
                        var drives = DriveInfo.GetDrives();
                        foreach (var driveInfo in drives)
                        {
                            // check disk space where application located
                            if (driveInfo.Name == _drvApp)
                            {
                                freeDiskSpaceApp = driveInfo.TotalFreeSpace;
                                totalDiskSpaceApp = driveInfo.TotalSize;
                            }

                            // check disk space where database located
                            if (driveInfo.Name == _drvDB)
                            {
                                freeDiskSpaceDB = driveInfo.TotalFreeSpace;
                                totalDiskSpaceDB = driveInfo.TotalSize;
                            }

                            _dbFreeDiskSpaceAmount = freeDiskSpaceDB;

                        }

                        // check APP free disk space low alarm
                        _rTrigAppFreeDiskSpaceLowAlarm.CLK = freeDiskSpaceApp < totalDiskSpaceApp * 0.05;
                        _rTrigAppFreeDiskSpaceLowWarn.CLK = freeDiskSpaceApp < totalDiskSpaceApp * 0.1;
                        if (_rTrigAppFreeDiskSpaceLowAlarm.Q) // Alarm detected
                            EV.PostAlarmLog(ModuleName.System.ToString(),
                                _drvApp + " Hard disk Free Space of Sic application is less than 5% ，need release");

                        else if (_rTrigAppFreeDiskSpaceLowWarn.Q) // Warning detected
                            EV.PostWarningLog(ModuleName.System.ToString(),
                                _drvApp + " Hard disk Free Space of Sic application is less than 10%，need release");

                        // check DB free disk space low alarm
                        _rTrigDBFreeDiskSpaceLowAlarm.CLK = freeDiskSpaceDB < 5 * GB_TO_BYTES;
                        _rTrigDBFreeDiskSpaceLowWarn.CLK = freeDiskSpaceDB < 20 * GB_TO_BYTES;
                        if (_rTrigDBFreeDiskSpaceLowAlarm.Q)
                        {
                            // Alarm detected
                            EV.PostAlarmLog(ModuleName.System.ToString(),
                                _drvDB + " Hard disk Free Space of Database is less than 5GB，need release");
                            _isDbFreeDiskSpaceLow = true;
                        }
                        else if (_rTrigDBFreeDiskSpaceLowWarn.Q)
                        {
                            // Warning detected
                            EV.PostWarningLog(ModuleName.System.ToString(),
                                _drvDB + " Hard disk Free Space of Database is less than 20GB，need release");
                            _isDbFreeDiskSpaceLow = true;
                        }

                        // No DB free disk space low warn and alarm
                        if (!_rTrigDBFreeDiskSpaceLowAlarm.M && !_rTrigDBFreeDiskSpaceLowWarn.M)
                        {
                            _isDbFreeDiskSpaceLow = false;
                        }

                        return true;
                    }, 1000, _rTrigMonitorTimeOver, out var duration, $"{nameof(DiskManager)}.{nameof(MonitorDiskSpace)}()");
            }
            catch (Exception ex)
            {
                LOG.Write(ex);
            }

            return true;
		}
		
		public void Stop()
		{
			_threadMonitorDiskSpace.Stop();
		}

		~DiskManager()
		{
			Stop();
		}
	}
}
