using GreenTree.Nachtragsmanagement.Core.Domain.Misc;
using GreenTree.Nachtragsmanagement.Services.Logging;
using GreenTree.Nachtragsmanagement.Services.Misc;
using Quartz;
using Quartz.Impl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace GreenTree.Nachtragsmanagement.Services.Scheduling
{
    public class NotificationScheduler : INotificationScheduler
    {
        #region Fields

        private readonly INotificationService _notificationService;
        private readonly IMiscService _miscService;
        private readonly ILogger _logger;

        #endregion

        #region Ctor

        /// <summary>
        /// Initializes a new instance of the NotificationScheduler class
        /// </summary>
        public NotificationScheduler(
            INotificationService notificationService,
            IMiscService miscService,
            ILogger logger)
        {
            _notificationService = notificationService;
            _miscService = miscService;
            _logger = logger;
        }

        #endregion

        /// <summary>
        /// Starts the scheduler and builds all corresponding notification jobs
        /// </summary>
        public void Start()
        {
            var scheduler = StdSchedulerFactory.GetDefaultScheduler();

            scheduler.Clear();
            scheduler.Start();

            var mailNotifications = _miscService.GetAllMailNotifications();

            foreach (var mailNotification in mailNotifications)
            {
                var notificationPlugin = _notificationService.GetNotificationPlugin(mailNotification.NotificationPluginSystemName);

                if (notificationPlugin == null)
                    continue;

                try
                {
                    var job = JobBuilder.Create(notificationPlugin.GetType())
                        .WithIdentity(mailNotification.Id.ToString())
                        .SetJobData(new JobDataMap
                        {
                                { "MailNotifications", new [] { mailNotification } }
                        })
                        .Build();

                    var trigger = TriggerBuilder.Create()
                        .WithCronSchedule(mailNotification.CronExpression)
                        .Build();

                    scheduler.ScheduleJob(job, trigger);

                    _logger.Information(
                        String.Format("Mailbenachrichtigung \"({0}) {1} - {2}\" erfolgreich eingeplant.", 
                            mailNotification.Id, mailNotification.NotificationPluginSystemName, 
                            mailNotification.NotificationJobSystemName));
                }
                catch (Exception ex)
                {
                    _logger.Error("Fehler beim Einplanen des Jobs für eine Mail-Benachrichtigung.", ex, null);
                }
            }
        }

        /// <summary>
        /// Determines the next execution time of a specific job
        /// </summary>
        /// <param name="jobId">The job id.</param>
        public DateTime GetNextExecutionOfJob(string jobId)
        {
            var scheduler = StdSchedulerFactory.GetDefaultScheduler();

            var jobKey = new JobKey(jobId);
            var nextFireTime = DateTime.MinValue;

            var isJobExisting = scheduler.CheckExists(jobKey);

            if (isJobExisting)
            {
                var detail = scheduler.GetJobDetail(jobKey);
                var triggers = scheduler.GetTriggersOfJob(jobKey);

                if (triggers.Count > 0)
                {
                    var nextFireTimeUtc = triggers[0].GetNextFireTimeUtc();

                    nextFireTime = TimeZone.CurrentTimeZone.ToLocalTime(nextFireTimeUtc.Value.DateTime);
                }
            }

            return (nextFireTime);
        }

        /// <summary>
        /// Determines the next execution time of a specific mail notification
        /// </summary>
        /// <param name="mailNotification">The mail notification job.</param>
        public DateTime GetNextExecutionOfJob(MailNotification mailNotification)
        {
            if (mailNotification == null)
                return DateTime.MinValue;

            return GetNextExecutionOfJob(mailNotification.Id.ToString());
        }
    }
}