using Managing.Domain.Users;
using static Managing.Common.Enums;

namespace Managing.Domain.Bots
{
    /// <summary>
    /// A bot define what code should be run. 
    /// To run a code you have to herit from this class and implement the Run() method
    /// </summary>
    public abstract class Bot : IBot
    {
        public int ExecutionCount;
        public string Identifier { get; set; }
        public string Name { get; set; }
        public int Interval { get; set; }
        public BotStatus Status { get; set; }
        public User User { get; set; }

        /// <summary>
        /// The time when the bot was started
        /// </summary>
        public DateTime StartupTime { get; private set; }

        private CancellationTokenSource CancellationToken { get; set; }

        public Bot(string name)
        {
            Identifier = $"{name}-{DateTime.Now:yyyyMMdd-hhmm}-{Guid.NewGuid()}";
            Name = name;
            Status = BotStatus.Down;
            CancellationToken = new CancellationTokenSource();
            ExecutionCount = 0;
            Interval = 3000;
            StartupTime = DateTime.MinValue; // Initialize with minimum value to indicate it hasn't been started yet
        }

        public virtual void Start()
        {
            Status = BotStatus.Up;
            StartupTime = DateTime.UtcNow; // Record the startup time when the bot is started
        }

        public async Task InitWorker(Func<Task> action)
        {
            try
            {
                await Task.Run(async () =>
                {
                    while (Status == BotStatus.Up && !CancellationToken.IsCancellationRequested)
                    {
                        try
                        {
                            await action();
                            ExecutionCount++;
                            await Task.Delay(Interval, CancellationToken.Token);
                            if (CancellationToken.IsCancellationRequested)
                                break;
                        }
                        catch (TaskCanceledException) when (CancellationToken.IsCancellationRequested)
                        {
                            // Graceful shutdown when cancellation is requested
                            break;
                        }
                        catch (Exception ex)
                        {
                            SentrySdk.CaptureException(ex);
                            Console.WriteLine(ex.Message);
                        }
                    }
                }, CancellationToken.Token);
            }
            catch (TaskCanceledException ex)
            {
                Console.WriteLine($"Bot was cancelled: {ex.Message}");
            }
        }

        public void Stop()
        {
            Status = BotStatus.Down;
            CancellationToken.Cancel();
        }

        public void Restart()
        {
            Status = BotStatus.Up;
            StartupTime = DateTime.UtcNow; // Update the startup time when the bot is restarted
        }

        public string GetStatus()
        {
            return Status.ToString();
        }

        public string GetName()
        {
            return Name;
        }

        /// <summary>
        /// Gets the total runtime of the bot since it was started
        /// </summary>
        /// <returns>TimeSpan representing the runtime, or TimeSpan.Zero if the bot is not running</returns>
        public TimeSpan GetRuntime()
        {
            if (Status != BotStatus.Up || StartupTime == DateTime.MinValue)
                return TimeSpan.Zero;

            return DateTime.UtcNow - StartupTime;
        }

        public abstract void SaveBackup();
        public abstract void LoadBackup(BotBackup backup);
    }
}