using Serilog;
using System;
using TINK.Settings;
using System.Threading.Tasks;

namespace TINK.ViewModel
{
    /// <summary>
    /// Performs a periodic update.
    /// </summary>
    public class PollingUpdateTaskManager : IPollingUpdateTaskManager
    {
        /// <summary>Name of child class provider. </summary>
        private readonly Func<string> m_oGetChildName;

        /// <summary> Action which performs an update.</summary>
        private Action m_oUpdateAction;

        /// <summary> Reference on the current polling task</summary>
        private PollingUpdateTask m_oPollingUpdateTask;

        /// <summary>
        /// Gets or sets polling parameters.
        /// </summary>
        private PollingParameters PollingParameters { get; set; }

        /// <summary> Prevents an invalid instance to be created. </summary>
        private PollingUpdateTaskManager()
        { }

        /// <summary>Constructs a update manager object. </summary>
        /// <param name="p_oGetChildName">Name of the child class. For logging purposes.</param>
        /// <param name="p_oUpdateAction"></param>
        public PollingUpdateTaskManager(
            Func<String> p_oGetChildName, 
            Action p_oUpdateAction)
        {
            m_oGetChildName = p_oGetChildName ?? throw new ArgumentException(
                $"Can not construct {GetType().Name}- obect. Argument {nameof(p_oGetChildName)} must not be null.");

            m_oUpdateAction = p_oUpdateAction ?? throw new ArgumentException(
                $"Can not construct {GetType().Name}- obect. Argument {nameof(p_oUpdateAction)} must not be null.");
        }
   
        /// <summary>
        /// Invoked when page is shown. 
        /// Actuates and awaits the first update process and starts a task wich actuate the subseqent update tasks.
        /// </summary>
        /// <param name="pollingParameters">Parametes holding polling periode, if null last parameters are used if available.</param>
        public async Task StartUpdateAyncPeridically(PollingParameters pollingParameters = null)
        {
            if (m_oPollingUpdateTask != null)
            {
                Log.Error($"Call to stop periodic update task missed in context {GetType().Name} at {DateTime.Now}.");

                // Call of StopUpdatePeriodically missed. 
                // Terminate running polling update task before starting a new one
                await m_oPollingUpdateTask.Terminate();
            }

            if (pollingParameters != null)
            {
                // Backup polling parameter for purposee of restart.
                PollingParameters = pollingParameters;
            }

            if (PollingParameters == null)
            {
                // No polling parameters avaialable.
                Log.Error($"Can not start polling. No parameters available.");
                return;
            }


            if (!PollingParameters.IsActivated)
            {
                // Automatic supdate is switched off.
                Log.ForContext<PollingUpdateTask>().Debug($"Automatic update is off, context {GetType().Name} at {DateTime.Now}.");
                return;
            }

            m_oPollingUpdateTask = new PollingUpdateTask(
                m_oGetChildName, 
                m_oUpdateAction,
                PollingParameters.Periode);
        }

        /// <summary>
        /// Invoked when pages is closed/ hidden. 
        /// Stops update process.
        /// </summary>
        public async Task StopUpdatePeridically()
        {
            if (m_oPollingUpdateTask == null)
            {
                // Nothing to do if there is no update task pending.
                return;
            }

            await m_oPollingUpdateTask.Terminate();

            m_oPollingUpdateTask = null;
        }
    }
}