using System;
using Server.Misc;

namespace Server.Saves
{
    public class AutoSave : Timer
    {
        private static Timer _autoSave;
        private static bool _enabled;
        private static DateTime _nextSave;

        public static TimeSpan Delay { get; private set; }
        public static TimeSpan Warning { get; private set; }

        public static bool SavesEnabled
        {
            get => _enabled;
            set
            {
                _enabled = value;

                if (value)
                {
                    SetNextSave(Core.Now.ToSystemLocalTime());
                    _autoSave ??= new AutoSave();
                    _autoSave.Start();
                }
                else
                {
                    _autoSave?.Stop();
                    _autoSave = null;
                }
            }
        }

        public static void Configure()
        {
            Delay = ServerConfiguration.GetOrUpdateSetting("autosave.saveDelay", TimeSpan.FromMinutes(5.0));
            Warning = ServerConfiguration.GetOrUpdateSetting("autosave.warningDelay", TimeSpan.Zero);
            SavesEnabled = ServerConfiguration.GetOrUpdateSetting("autosave.enabled", true);
        }

        public static void ResetAutoSave(TimeSpan saveDelay, TimeSpan warningDelay)
        {
            if (saveDelay != Delay || warningDelay != Warning)
            {
                Delay = saveDelay;
                Warning = warningDelay;

                ServerConfiguration.SetSetting("autosave.saveDelay", Delay);
                ServerConfiguration.SetSetting("autosave.warningDelay", Warning);
            }

            SavesEnabled = true;
        }

        private static void SetNextSave(DateTime now)
        {
            var timeOfDay = now.TimeOfDay;
            var delay = Delay.Ticks;

            _nextSave = (now + TimeSpan.FromTicks(delay - timeOfDay.Ticks % delay) - Warning).ToUniversalTime();
        }

        public AutoSave() : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
        {
        }

        protected override void OnTick()
        {
            if (_nextSave > Core.Now)
            {
                return;
            }

            if (SavesEnabled && !AutoRestart.Restarting && !Core.Closing && !World.Saving)
            {
                if (Warning > TimeSpan.Zero)
                {
                    BroadcastWarning();
                    StartTimer(Warning, Save);
                }
                else
                {
                    Save();
                }
            }

            _nextSave += Delay;
        }

        private static void BroadcastWarning()
        {
            var m = Math.DivRem((int)Math.Round(Warning.TotalSeconds), 60, out var s);

            if (m > 0 && s > 0)
            {
                World.Broadcast(
                    0x35,
                    true,
                    $"The world will save in {m} minute{(m != 1 ? "s" : "")} and {s} second{(s != 1 ? "s" : "")}."
                );
            }
            else if (m > 0)
            {
                World.Broadcast(0x35, true, $"The world will save in {m} minute{(m != 1 ? "s" : "")}.");
            }
            else
            {
                World.Broadcast(0x35, true, $"The world will save in {s} second{(s != 1 ? "s" : "")}.");
            }
        }

        public static void Save()
        {
            if (!AutoRestart.Restarting && World.Running)
            {
                World.Save();
            }
        }
    }
}
