using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Haoliang.Models.System;
using Haoliang.Models.Device;
using Haoliang.Data.Repositories;

namespace Haoliang.Core.Services
{
    public interface IAlarmNotificationService
    {
        Task SendAlarmNotificationAsync(Alarm alarm);
        Task SendBulkAlarmNotificationsAsync(IEnumerable<Alarm> alarms);
        Task<bool> SendSmsNotificationAsync(string phoneNumber, string message);
        Task<bool> SendEmailNotificationAsync(string email, string subject, string message);
        Task<bool> SendWechatNotificationAsync(string openId, string message);
        Task<IEnumerable<AlarmNotification>> GetNotificationHistoryAsync(DateTime startDate, DateTime endDate);
        Task<bool> ConfigureNotificationChannelAsync(NotificationChannel channel);
        Task<IEnumerable<NotificationChannel>> GetAvailableChannelsAsync();
        Task TestNotificationChannelAsync(NotificationChannel channel);
        Task<int> GetFailedNotificationCountAsync(DateTime date);
        Task<bool> ResendFailedNotificationsAsync(int maxRetries = 3);
    }

    public class AlarmNotificationService : IAlarmNotificationService
    {
        private readonly IAlarmNotificationRepository _notificationRepository;
        private readonly ISystemConfigRepository _configRepository;
        private readonly ILoggingService _loggingService;
        private readonly INotificationSender _smsSender;
        private readonly INotificationSender _emailSender;
        private readonly INotificationSender _wechatSender;
        private readonly ConcurrentDictionary<string, NotificationChannel> _channels;

        public AlarmNotificationService(
            IAlarmNotificationRepository notificationRepository,
            ISystemConfigRepository configRepository,
            ILoggingService loggingService,
            INotificationSender smsSender,
            INotificationSender emailSender,
            INotificationSender wechatSender)
        {
            _notificationRepository = notificationRepository;
            _configRepository = configRepository;
            _loggingService = loggingService;
            _smsSender = smsSender;
            _emailSender = emailSender;
            _wechatSender = wechatSender;
            _channels = new ConcurrentDictionary<string, NotificationChannel>();
        }

        public async Task SendAlarmNotificationAsync(Alarm alarm)
        {
            if (alarm == null)
                throw new ArgumentNullException(nameof(alarm));

            if (!alarm.IsActive)
            {
                await _loggingService.LogDebugAsync($"Skipping notification for inactive alarm {alarm.AlarmId}");
                return;
            }

            // Get notification channels for this alarm
            var channels = await GetNotificationChannelsForAlarm(alarm);
            
            foreach (var channel in channels)
            {
                try
                {
                    await SendNotificationViaChannelAsync(alarm, channel);
                }
                catch (Exception ex)
                {
                    await _loggingService.LogErrorAsync($"Failed to send alarm {alarm.AlarmId} via {channel.ChannelType}: {ex.Message}", ex);
                }
            }
        }

        public async Task SendBulkAlarmNotificationsAsync(IEnumerable<Alarm> alarms)
        {
            if (alarms == null)
                throw new ArgumentNullException(nameof(alarms));

            var alarmList = alarms.ToList();
            await _loggingService.LogInformationAsync($"Processing bulk notifications for {alarmList.Count} alarms");

            var notificationTasks = alarmList.Select(alarm => SendAlarmNotificationAsync(alarm));
            await Task.WhenAll(notificationTasks);

            await _loggingService.LogInformationAsync($"Completed bulk notifications for {alarmList.Count} alarms");
        }

        public async Task<bool> SendSmsNotificationAsync(string phoneNumber, string message)
        {
            try
            {
                var smsConfig = await GetSmsConfigurationAsync();
                if (!smsConfig.IsEnabled)
                {
                    await _loggingService.LogWarningAsync("SMS notifications are disabled");
                    return false;
                }

                var result = await _smsSender.SendAsync(phoneNumber, message, smsConfig);
                
                if (result.Success)
                {
                    await _loggingService.LogInformationAsync($"SMS sent successfully to {phoneNumber}");
                }
                else
                {
                    await _loggingService.LogErrorAsync($"SMS failed to {phoneNumber}: {result.ErrorMessage}");
                }

                return result.Success;
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"SMS notification error: {ex.Message}", ex);
                return false;
            }
        }

        public async Task<bool> SendEmailNotificationAsync(string email, string subject, string message)
        {
            try
            {
                var emailConfig = await GetEmailConfigurationAsync();
                if (!emailConfig.IsEnabled)
                {
                    await _loggingService.LogWarningAsync("Email notifications are disabled");
                    return false;
                }

                var result = await _emailSender.SendAsync(email, subject, message, emailConfig);
                
                if (result.Success)
                {
                    await _loggingService.LogInformationAsync($"Email sent successfully to {email}");
                }
                else
                {
                    await _loggingService.LogErrorAsync($"Email failed to {email}: {result.ErrorMessage}");
                }

                return result.Success;
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Email notification error: {ex.Message}", ex);
                return false;
            }
        }

        public async Task<bool> SendWechatNotificationAsync(string openId, string message)
        {
            try
            {
                var wechatConfig = await GetWechatConfigurationAsync();
                if (!wechatConfig.IsEnabled)
                {
                    await _loggingService.LogWarningAsync("WeChat notifications are disabled");
                    return false;
                }

                var result = await _wechatSender.SendAsync(openId, message, wechatConfig);
                
                if (result.Success)
                {
                    await _loggingService.LogInformationAsync($"WeChat message sent successfully to {openId}");
                }
                else
                {
                    await _loggingService.LogErrorAsync($"WeChat message failed to {openId}: {result.ErrorMessage}");
                }

                return result.Success;
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"WeChat notification error: {ex.Message}", ex);
                return false;
            }
        }

        public async Task<IEnumerable<AlarmNotification>> GetNotificationHistoryAsync(DateTime startDate, DateTime endDate)
        {
            return await _notificationRepository.GetNotificationsByDateRangeAsync(startDate, endDate);
        }

        public async Task<bool> ConfigureNotificationChannelAsync(NotificationChannel channel)
        {
            if (channel == null)
                throw new ArgumentNullException(nameof(channel));

            // Validate channel configuration
            if (!await ValidateChannelConfigurationAsync(channel))
                return false;

            // Save channel configuration
            await _configRepository.UpsertAsync(new SystemConfig
            {
                ConfigKey = $"notification_{channel.ChannelType}_enabled",
                ConfigValue = channel.IsEnabled.ToString(),
                Category = "Notification",
                Description = $"Enable {channel.ChannelType} notifications"
            });

            await _configRepository.UpsertAsync(new SystemConfig
            {
                ConfigKey = $"notification_{channel.ChannelType}_config",
                ConfigValue = System.Text.Json.JsonSerializer.Serialize(channel.Settings),
                Category = "Notification",
                Description = $"{channel.ChannelType} notification settings"
            });

            _channels[channel.ChannelType] = channel;
            
            await _loggingService.LogInformationAsync($"Configured notification channel: {channel.ChannelType}");
            return true;
        }

        public async Task<IEnumerable<NotificationChannel>> GetAvailableChannelsAsync()
        {
            var channels = new List<NotificationChannel>();

            // SMS Channel
            if (await IsChannelEnabledAsync("SMS"))
            {
                channels.Add(new NotificationChannel
                {
                    ChannelType = "SMS",
                    IsEnabled = true,
                    Settings = await GetSmsConfigurationAsync()
                });
            }

            // Email Channel
            if (await IsChannelEnabledAsync("Email"))
            {
                channels.Add(new NotificationChannel
                {
                    ChannelType = "Email",
                    IsEnabled = true,
                    Settings = await GetEmailConfigurationAsync()
                });
            }

            // WeChat Channel
            if (await IsChannelEnabledAsync("WeChat"))
            {
                channels.Add(new NotificationChannel
                {
                    ChannelType = "WeChat",
                    IsEnabled = true,
                    Settings = await GetWechatConfigurationAsync()
                });
            }

            return channels;
        }

        public async Task TestNotificationChannelAsync(NotificationChannel channel)
        {
            if (channel == null)
                throw new ArgumentNullException(nameof(channel));

            var testMessage = $"This is a test notification from CNC System at {DateTime.Now:yyyy-MM-dd HH:mm:ss}";

            switch (channel.ChannelType)
            {
                case "SMS":
                    await SendSmsNotificationAsync(channel.TestPhoneNumber, testMessage);
                    break;
                case "Email":
                    await SendEmailNotificationAsync(channel.TestEmail, "CNC System Test", testMessage);
                    break;
                case "WeChat":
                    await SendWechatNotificationAsync(channel.TestOpenId, testMessage);
                    break;
                default:
                    throw new ArgumentException($"Unsupported channel type: {channel.ChannelType}");
            }

            await _loggingService.LogInformationAsync($"Test notification sent via {channel.ChannelType}");
        }

        public async Task<int> GetFailedNotificationCountAsync(DateTime date)
        {
            var startOfDay = date.Date;
            var endOfDay = startOfDay.AddDays(1);

            return await _notificationRepository.GetFailedNotificationsCountAsync(startOfDay, endOfDay);
        }

        public async Task<bool> ResendFailedNotificationsAsync(int maxRetries = 3)
        {
            var failedNotifications = await _notificationRepository.GetFailedNotificationsAsync(maxRetries);
            
            if (!failedNotifications.Any())
            {
                await _loggingService.LogInformationAsync("No failed notifications to resend");
                return true;
            }

            var successCount = 0;
            var retryTasks = failedNotifications.Select(async notification =>
            {
                try
                {
                    await RetryFailedNotificationAsync(notification);
                    successCount++;
                }
                catch (Exception ex)
                {
                    await _loggingService.LogErrorAsync($"Failed to resend notification {notification.NotificationId}: {ex.Message}", ex);
                }
            });

            await Task.WhenAll(retryTasks);

            await _loggingService.LogInformationAsync($"Resent {successCount}/{failedNotifications.Count} failed notifications");
            return successCount > 0;
        }

        private async Task<IEnumerable<NotificationChannel>> GetNotificationChannelsForAlarm(Alarm alarm)
        {
            var channels = new List<NotificationChannel>();
            var alarmType = alarm.AlarmType.ToLower();

            // Get global notification settings
            var smsEnabled = await IsChannelEnabledAsync("SMS");
            var emailEnabled = await IsChannelEnabledAsync("Email");
            var wechatEnabled = await IsChannelEnabledAsync("WeChat");

            // High severity alarms get all channels
            if (alarm.AlarmSeverity == AlarmSeverity.Critical || alarm.AlarmSeverity == AlarmSeverity.High)
            {
                if (smsEnabled) channels.Add(await CreateSmsChannelAsync());
                if (emailEnabled) channels.Add(await CreateEmailChannelAsync());
                if (wechatEnabled) channels.Add(await CreateWechatChannelAsync());
            }
            // Medium severity alarms get email and SMS
            else if (alarm.AlarmSeverity == AlarmSeverity.Medium)
            {
                if (emailEnabled) channels.Add(await CreateEmailChannelAsync());
                if (smsEnabled) channels.Add(await CreateSmsChannelAsync());
            }
            // Low severity alarms get email only
            else if (alarm.AlarmSeverity == AlarmSeverity.Low && emailEnabled)
            {
                channels.Add(await CreateEmailChannelAsync());
            }

            return channels;
        }

        private async Task SendNotificationViaChannelAsync(Alarm alarm, NotificationChannel channel)
        {
            var subject = $"CNC Alarm: {alarm.AlarmType} - {alarm.DeviceName}";
            var message = CreateAlarmMessage(alarm);

            switch (channel.ChannelType)
            {
                case "SMS":
                    await SendSmsNotificationAsync(channel.Recipients.FirstOrDefault(), message);
                    break;
                case "Email":
                    await SendEmailNotificationAsync(channel.Recipients.FirstOrDefault(), subject, message);
                    break;
                case "WeChat":
                    await SendWechatNotificationAsync(channel.Recipients.FirstOrDefault(), message);
                    break;
            }
        }

        private string CreateAlarmMessage(Alarm alarm)
        {
            return $@"
🚨 CNC System Alarm Alert 🚨

Device: {alarm.DeviceName} ({alarm.DeviceCode})
Type: {alarm.AlarmType}
Severity: {alarm.AlarmSeverity}
Time: {alarm.CreateTime:yyyy-MM-dd HH:mm:ss}

Description: {alarm.Title}

Please take immediate action.
".Trim();
        }

        private async Task<NotificationSettings> GetSmsConfigurationAsync()
        {
            // Get SMS configuration from database or use defaults
            return new NotificationSettings
            {
                IsEnabled = true,
                ApiKey = await _configRepository.GetValueAsync("sms_api_key") ?? "",
                ApiSecret = await _configRepository.GetValueAsync("sms_api_secret") ?? "",
                Provider = await _configRepository.GetValueAsync("sms_provider") ?? "twilio"
            };
        }

        private async Task<NotificationSettings> GetEmailConfigurationAsync()
        {
            return new NotificationSettings
            {
                IsEnabled = true,
                SmtpServer = await _configRepository.GetValueAsync("smtp_server") ?? "smtp.gmail.com",
                SmtpPort = int.Parse(await _configRepository.GetValueAsync("smtp_port") ?? "587"),
                Username = await _configRepository.GetValueAsync("smtp_username") ?? "",
                Password = await _configRepository.GetValueAsync("smtp_password") ?? "",
                UseSsl = bool.Parse(await _configRepository.GetValueAsync("smtp_ssl") ?? "true")
            };
        }

        private async Task<NotificationSettings> GetWechatConfigurationAsync()
        {
            return new NotificationSettings
            {
                IsEnabled = true,
                AppId = await _configRepository.GetValueAsync("wechat_app_id") ?? "",
                AppSecret = await _configRepository.GetValueAsync("wechat_app_secret") ?? "",
                TemplateId = await _configRepository.GetValueAsync("wechat_template_id") ?? ""
            };
        }

        private async Task<bool> IsChannelEnabledAsync(string channelType)
        {
            var configKey = $"notification_{channelType}_enabled";
            var configValue = await _configRepository.GetValueAsync(configKey);
            return bool.TryParse(configValue, out bool enabled) && enabled;
        }

        private async Task<bool> ValidateChannelConfigurationAsync(NotificationChannel channel)
        {
            // Add validation logic based on channel type
            switch (channel.ChannelType)
            {
                case "SMS":
                    return !string.IsNullOrEmpty(channel.TestPhoneNumber);
                case "Email":
                    return !string.IsNullOrEmpty(channel.TestEmail);
                case "WeChat":
                    return !string.IsNullOrEmpty(channel.TestOpenId);
                default:
                    return false;
            }
        }

        private async Task<NotificationChannel> CreateSmsChannelAsync()
        {
            return new NotificationChannel
            {
                ChannelType = "SMS",
                IsEnabled = true,
                Recipients = await GetSmsRecipientsAsync(),
                TestPhoneNumber = await _configRepository.GetValueAsync("sms_test_phone") ?? "+1234567890",
                Settings = await GetSmsConfigurationAsync()
            };
        }

        private async Task<NotificationChannel> CreateEmailChannelAsync()
        {
            return new NotificationChannel
            {
                ChannelType = "Email",
                IsEnabled = true,
                Recipients = await GetEmailRecipientsAsync(),
                TestEmail = await _configRepository.GetValueAsync("email_test_address") ?? "test@example.com",
                Settings = await GetEmailConfigurationAsync()
            };
        }

        private async Task<NotificationChannel> CreateWechatChannelAsync()
        {
            return new NotificationChannel
            {
                ChannelType = "WeChat",
                IsEnabled = true,
                Recipients = await GetWechatRecipientsAsync(),
                TestOpenId = await _configRepository.GetValueAsync("wechat_test_openid") ?? "test_openid",
                Settings = await GetWechatConfigurationAsync()
            };
        }

        private async Task<List<string>> GetSmsRecipientsAsync()
        {
            var configValue = await _configRepository.GetValueAsync("sms_recipients");
            return string.IsNullOrEmpty(configValue) ? new List<string>() : configValue.Split(',').Select(s => s.Trim()).ToList();
        }

        private async Task<List<string>> GetEmailRecipientsAsync()
        {
            var configValue = await _configRepository.GetValueAsync("email_recipients");
            return string.IsNullOrEmpty(configValue) ? new List<string>() : configValue.Split(',').Select(s => s.Trim()).ToList();
        }

        private async Task<List<string>> GetWechatRecipientsAsync()
        {
            var configValue = await _configRepository.GetValueAsync("wechat_recipients");
            return string.IsNullOrEmpty(configValue) ? new List<string>() : configValue.Split(',').Select(s => s.Trim()).ToList();
        }

        private async Task RetryFailedNotificationAsync(AlarmNotification notification)
        {
            // Retry logic here
            await _notificationRepository.MarkAsRetriedAsync(notification.NotificationId);
        }
    }

    // Supporting interfaces and classes
    public interface INotificationSender
    {
        Task<NotificationResult> SendAsync(string recipient, string message, NotificationSettings settings);
    }

    public class NotificationResult
    {
        public bool Success { get; set; }
        public string ErrorMessage { get; set; }
        public string ReferenceId { get; set; }
    }

    public class NotificationSettings
    {
        public bool IsEnabled { get; set; }
        public string ApiKey { get; set; }
        public string ApiSecret { get; set; }
        public string Provider { get; set; }
        public string SmtpServer { get; set; }
        public int SmtpPort { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public bool UseSsl { get; set; }
        public string AppId { get; set; }
        public string AppSecret { get; set; }
        public string TemplateId { get; set; }
    }

    // Additional repository interface for alarm notifications
    public interface IAlarmNotificationRepository : IRepository<AlarmNotification>
    {
        Task<IEnumerable<AlarmNotification>> GetNotificationsByDateRangeAsync(DateTime startDate, DateTime endDate);
        Task<IEnumerable<AlarmNotification>> GetFailedNotificationsAsync(int maxRetries = 3);
        Task<int> GetFailedNotificationsCountAsync(DateTime startDate, DateTime endDate);
        Task<bool> MarkAsRetriedAsync(int notificationId);
        Task<IEnumerable<AlarmNotification>> GetNotificationsByAlarmAsync(int alarmId);
    }
}