using EDAViewer.Singleton;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Shared;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace EDAViewer.HostedService
{

    public class TimedHostedService : IHostedService, IDisposable
    {

        private readonly int _ExecutionCount;
        private readonly Background _Background;
        private readonly IsEnvironment _IsEnvironment;
        private readonly ILogger<TimedHostedService> _Log;

        private Timer _EDAOutputArchiveTimer;
        private Timer _LogPathCleanUpByWeekTimer;
        private Timer _EdaDataCollectionPlansTimer;

        public TimedHostedService(IsEnvironment isEnvironment, Background background, IServiceProvider serviceProvider)
        {
            _ExecutionCount = 0;
            _Background = background;
            _IsEnvironment = isEnvironment;
            _Log = serviceProvider.GetRequiredService<ILogger<TimedHostedService>>();
            _EDAOutputArchiveTimer = new Timer(EDAOutputArchiveCallback, null, Timeout.Infinite, Timeout.Infinite);
            _LogPathCleanUpByWeekTimer = new Timer(LogPathCleanUpByWeekCallback, null, Timeout.Infinite, Timeout.Infinite);
            _EdaDataCollectionPlansTimer = new Timer(EdaDataCollectionPlansCallback, null, Timeout.Infinite, Timeout.Infinite);
        }

        public Task StartAsync(CancellationToken stoppingToken)
        {
            _Log.LogInformation(string.Concat("Timed Hosted Service: ", nameof(Background), ":", _IsEnvironment.Profile, ":", Environment.ProcessId, " running."));
            _Background.Update(_Log);
            if (_IsEnvironment.Development)
            {
                int milliSeconds = 3000;
                _EdaDataCollectionPlansTimer.Change(milliSeconds, Timeout.Infinite);
                ;
                _Background.Timers.Add(_EdaDataCollectionPlansTimer);
                milliSeconds += 2000;
            }
            else if (_IsEnvironment.Staging)
            {
                int milliSeconds = 3000;
                _LogPathCleanUpByWeekTimer.Change(milliSeconds, Timeout.Infinite);
                ;
                _Background.Timers.Add(_LogPathCleanUpByWeekTimer);
                milliSeconds += 2000;
                _EdaDataCollectionPlansTimer.Change(milliSeconds, Timeout.Infinite);
                ;
                _Background.Timers.Add(_EdaDataCollectionPlansTimer);
                milliSeconds += 2000;
                _EDAOutputArchiveTimer.Change(milliSeconds, Timeout.Infinite);
                ;
                _Background.Timers.Add(_EDAOutputArchiveTimer);
                milliSeconds += 2000;
            }
            else if (_IsEnvironment.Production)
            {
                int milliSeconds = 3000;
                _LogPathCleanUpByWeekTimer.Change(milliSeconds, Timeout.Infinite);
                ;
                _Background.Timers.Add(_LogPathCleanUpByWeekTimer);
                milliSeconds += 2000;
                _EdaDataCollectionPlansTimer.Change(milliSeconds, Timeout.Infinite);
                ;
                _Background.Timers.Add(_EdaDataCollectionPlansTimer);
                milliSeconds += 2000;
                _EDAOutputArchiveTimer.Change(milliSeconds, Timeout.Infinite);
                ;
                _Background.Timers.Add(_EDAOutputArchiveTimer);
                milliSeconds += 2000;
            }
            else
                throw new Exception();
            if (_IsEnvironment.Staging || _IsEnvironment.Production)
            {
                string countDirectory = _Background.GetCountDirectory("Start");
                string checkDirectory = Path.GetPathRoot(countDirectory);
                if (Directory.Exists(checkDirectory))
                    Directory.CreateDirectory(countDirectory);
            }
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken stoppingToken)
        {
            _Log.LogInformation(string.Concat("Timed Hosted Service: ", nameof(Background), ":", _IsEnvironment.Profile, ":", Environment.ProcessId, " is stopping."));
            _Background.Stop(immediate: true);
            for (short i = 0; i < short.MaxValue; i++)
            {
                Thread.Sleep(500);
                if (_ExecutionCount == 0)
                    break;
            }
            return Task.CompletedTask;
        }

        public void Dispose()
        {
            _Background.Dispose();
        }

        private void LogPathCleanUpByWeekCallback(object state)
        {
            try
            {
                if (_Background.IsPrimaryInstance())
                    _Background.LogPathCleanUpByWeekCallback();
            }
            catch (Exception e) { _Background.Catch(e); }
            try
            {
                TimeSpan timeSpan;
                if (!_Background.IsPrimaryInstance())
                    timeSpan = new TimeSpan(DateTime.Now.AddSeconds(15).Ticks - DateTime.Now.Ticks);
                else
                    timeSpan = new TimeSpan(DateTime.Now.AddHours(6).Ticks - DateTime.Now.Ticks);
                _LogPathCleanUpByWeekTimer.Change((int)timeSpan.TotalMilliseconds, Timeout.Infinite);
            }
            catch (Exception e) { _Background.Catch(e); }
        }

        private void EDAOutputArchiveCallback(object state)
        {
            try
            {
                if (_Background.IsPrimaryInstance())
                    _Background.EDAOutputArchiveCallback();
            }
            catch (Exception e) { _Background.Catch(e); }
            try
            {
                TimeSpan timeSpan;
                if (!_Background.IsPrimaryInstance())
                    timeSpan = new TimeSpan(DateTime.Now.AddSeconds(15).Ticks - DateTime.Now.Ticks);
                else
                    timeSpan = new TimeSpan(DateTime.Now.AddHours(6).Ticks - DateTime.Now.Ticks);
                _EDAOutputArchiveTimer.Change((int)timeSpan.TotalMilliseconds, Timeout.Infinite);
            }
            catch (Exception e) { _Background.Catch(e); }
        }

        private void EdaDataCollectionPlansCallback(object state)
        {
            try
            {
                if (_Background.IsPrimaryInstance())
                    _Background.EdaDataCollectionPlansCallback();
            }
            catch (Exception e) { _Background.Catch(e); }
            try
            {
                TimeSpan timeSpan;
                if (!_Background.IsPrimaryInstance())
                    timeSpan = new TimeSpan(DateTime.Now.AddSeconds(15).Ticks - DateTime.Now.Ticks);
                else
                    timeSpan = new TimeSpan(DateTime.Now.AddHours(2).Ticks - DateTime.Now.Ticks);
                _EdaDataCollectionPlansTimer.Change((int)timeSpan.TotalMilliseconds, Timeout.Infinite);
            }
            catch (Exception e) { _Background.Catch(e); }
        }


    }

}