using EDAViewer.Models.Methods;
using EDAViewer.Models.Stateless;
using EDAViewer.Models.Stateless.Methods;
using EDAViewer.Singleton;
using IFX.Shared;
using Serilog.Context;

namespace EDAViewer.HostedService;

public class TimedHostedService : IHostedService, IDisposable
{

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

    private readonly int _ExecutionCount;
    private readonly Serilog.ILogger _Log;
    private readonly IsEnvironment _IsEnvironment;
    private readonly IBackground _BackgroundMethods;
    private readonly Models.Properties.IBackground _Background;

    public TimedHostedService(IsEnvironment isEnvironment, Background background)
    {
        _ExecutionCount = 0;
        _Background = background;
        _IsEnvironment = isEnvironment;
        _BackgroundMethods = background;
        _Log = Serilog.Log.ForContext<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)
    {
        string? methodName = IMethodName.GetActualAsyncMethodName();
        using (LogContext.PushProperty("MethodName", methodName))
        {
            _Log.Info(string.Concat("Timed Hosted Service: ", _IsEnvironment.Profile, ":", Environment.ProcessId, " running."));
            int milliSeconds = 3000;
            if (_IsEnvironment.Development)
            {
                _BackgroundMethods.Update(milliSeconds);
                _ = _EdaDataCollectionPlansTimer.Change(milliSeconds, Timeout.Infinite);
                _Background.Timers.Add(_EdaDataCollectionPlansTimer);
                milliSeconds += 2000;
            }
            else if (_IsEnvironment.Staging)
            {
                _BackgroundMethods.Update(milliSeconds);
                _ = _EdaDataCollectionPlansTimer.Change(milliSeconds, Timeout.Infinite);
                _Background.Timers.Add(_EdaDataCollectionPlansTimer);
                milliSeconds += 2000;
                _ = _EDAOutputArchiveTimer.Change(milliSeconds, Timeout.Infinite);
                _Background.Timers.Add(_EDAOutputArchiveTimer);
                milliSeconds += 2000;
                _ = _LogPathCleanUpByWeekTimer.Change(milliSeconds, Timeout.Infinite);
                _Background.Timers.Add(_LogPathCleanUpByWeekTimer);
                milliSeconds += 2000;
            }
            else if (_IsEnvironment.Production)
            {
                _BackgroundMethods.Update(milliSeconds);
                _ = _EdaDataCollectionPlansTimer.Change(milliSeconds, Timeout.Infinite);
                _Background.Timers.Add(_EdaDataCollectionPlansTimer);
                milliSeconds += 2000;
                _ = _EDAOutputArchiveTimer.Change(milliSeconds, Timeout.Infinite);
                _Background.Timers.Add(_EDAOutputArchiveTimer);
                milliSeconds += 2000;
                _ = _LogPathCleanUpByWeekTimer.Change(milliSeconds, Timeout.Infinite);
                _Background.Timers.Add(_LogPathCleanUpByWeekTimer);
                milliSeconds += 2000;
            }
            else
                throw new Exception();
            if (_IsEnvironment.Staging || _IsEnvironment.Production)
            {
                string countDirectory = _BackgroundMethods.GetCountDirectory("Start");
                string? checkDirectory = Path.GetPathRoot(countDirectory);
                if (Directory.Exists(checkDirectory))
                    _ = Directory.CreateDirectory(countDirectory);
            }
        }
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken stoppingToken)
    {
        string? methodName = IMethodName.GetActualAsyncMethodName();
        using (LogContext.PushProperty("MethodName", methodName))
        {
            _Log.Info(string.Concat("Timed Hosted Service: ", _IsEnvironment.Profile, ":", Environment.ProcessId, " is stopping."));
            _BackgroundMethods.Stop(immediate: true);
            for (short i = 0; i < short.MaxValue; i++)
            {
                Thread.Sleep(500);
                if (_ExecutionCount == 0)
                    break;
            }
        }
        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _BackgroundMethods.Dispose();
        GC.SuppressFinalize(this);
    }

    private void LogPathCleanUpByWeekCallback(object? state)
    {
        try
        {
            if (_BackgroundMethods.IsPrimaryInstance())
                _BackgroundMethods.LogPathCleanUpByWeekCallback();
        }
        catch (Exception e) { _Log.Error(e, "Error: "); }
        try
        {
            TimeSpan timeSpan;
            if (!_BackgroundMethods.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) { _Log.Error(e, "Error: "); }
    }

    private void EDAOutputArchiveCallback(object? state)
    {
        try
        {
            if (_BackgroundMethods.IsPrimaryInstance())
                _BackgroundMethods.EDAOutputArchiveCallback();
        }
        catch (Exception e) { _Log.Error(e, "Error: "); }
        try
        {
            TimeSpan timeSpan;
            if (!_BackgroundMethods.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) { _Log.Error(e, "Error: "); }
    }

    private void EdaDataCollectionPlansCallback(object? state)
    {
        try
        {
            if (_BackgroundMethods.IsPrimaryInstance())
                _BackgroundMethods.EdaDataCollectionPlansCallback();
        }
        catch (Exception e) { _Log.Error(e, "Error: "); }
        try
        {
            TimeSpan timeSpan;
            if (!_BackgroundMethods.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) { _Log.Error(e, "Error: "); }
    }

}