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

namespace Haoliang.Core.Services
{
    public interface IAlarmService
    {
        Task<Alarm> CreateAlarmAsync(Alarm alarm);
        Task<Alarm> UpdateAlarmAsync(int alarmId, Alarm alarm);
        Task<bool> DeleteAlarmAsync(int alarmId);
        Task<Alarm> GetAlarmByIdAsync(int alarmId);
        Task<IEnumerable<Alarm>> GetAllAlarmsAsync();
        Task<IEnumerable<Alarm>> GetAlarmsByDeviceAsync(int deviceId);
        Task<IEnumerable<Alarm>> GetAlarmsByTypeAsync(AlarmType type);
        Task<IEnumerable<Alarm>> GetActiveAlarmsAsync();
        Task<IEnumerable<Alarm>> GetAlarmsByDateRangeAsync(DateTime startDate, DateTime endDate);
        Task<bool> ResolveAlarmAsync(int alarmId, string resolutionNote);
        Task<bool> AcknowledgeAlarmAsync(int alarmId, string acknowledgeNote);
        Task<AlarmStatistics> GetAlarmStatisticsAsync(DateTime date);
        Task<IEnumerable<Alarm>> GetCriticalAlarmsAsync();
        Task<IEnumerable<Alarm>> GetDeviceAlarmsAsync(int deviceId, int days = 7);
    }

    public interface IAlarmRuleService
    {
        Task<AlarmRule> CreateAlarmRuleAsync(AlarmRule rule);
        Task<AlarmRule> UpdateAlarmRuleAsync(int ruleId, AlarmRule rule);
        Task<bool> DeleteAlarmRuleAsync(int ruleId);
        Task<AlarmRule> GetAlarmRuleByIdAsync(int ruleId);
        Task<IEnumerable<AlarmRule>> GetAllAlarmRulesAsync();
        Task<IEnumerable<AlarmRule>> GetActiveAlarmRulesAsync();
        Task<IEnumerable<AlarmRule>> GetRulesByDeviceAsync(int deviceId);
        Task<bool> EvaluateAlarmRuleAsync(AlarmRule rule, DeviceCurrentStatus status);
        Task<Alarm> GenerateAlarmFromRuleAsync(AlarmRule rule, DeviceCurrentStatus status);
        Task TestAlarmRuleAsync(int ruleId);
    }

    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();
    }

    public class AlarmManager : IAlarmService
    {
        private readonly IAlarmRepository _alarmRepository;
        private readonly IAlarmRuleService _alarmRuleService;
        private readonly IAlarmNotificationService _notificationService;

        public AlarmManager(
            IAlarmRepository alarmRepository,
            IAlarmRuleService alarmRuleService,
            IAlarmNotificationService notificationService)
        {
            _alarmRepository = alarmRepository;
            _alarmRuleService = alarmRuleService;
            _notificationService = notificationService;
        }

        public async Task<Alarm> CreateAlarmAsync(Alarm alarm)
        {
            // 设置初始状态
            alarm.AlarmStatus = AlarmStatus.Active;
            alarm.CreateTime = DateTime.Now;
            alarm.UpdateTime = DateTime.Now;
            
            var createdAlarm = await _alarmRepository.AddAsync(alarm);
            
            // 发送告警通知
            await _notificationService.SendAlarmNotificationAsync(createdAlarm);
            
            return createdAlarm;
        }

        public async Task<Alarm> UpdateAlarmAsync(int alarmId, Alarm alarm)
        {
            var existingAlarm = await _alarmRepository.GetByIdAsync(alarmId);
            if (existingAlarm == null)
            {
                throw new KeyNotFoundException($"Alarm with ID {alarmId} not found");
            }

            // 更新字段
            alarm.AlarmId = alarmId;
            alarm.UpdateTime = DateTime.Now;
            
            var updatedAlarm = await _alarmRepository.UpdateAsync(alarm);
            return updatedAlarm;
        }

        public async Task<bool> DeleteAlarmAsync(int alarmId)
        {
            return await _alarmRepository.DeleteAsync(alarmId);
        }

        public async Task<Alarm> GetAlarmByIdAsync(int alarmId)
        {
            return await _alarmRepository.GetByIdAsync(alarmId);
        }

        public async Task<IEnumerable<Alarm>> GetAllAlarmsAsync()
        {
            return await _alarmRepository.GetAllAsync();
        }

        public async Task<IEnumerable<Alarm>> GetAlarmsByDeviceAsync(int deviceId)
        {
            return await _alarmRepository.GetByDeviceIdAsync(deviceId);
        }

        public async Task<IEnumerable<Alarm>> GetAlarmsByTypeAsync(AlarmType type)
        {
            return await _alarmRepository.GetByAlarmTypeAsync(type);
        }

        public async Task<IEnumerable<Alarm>> GetActiveAlarmsAsync()
        {
            return await _alarmRepository.GetByStatusAsync(AlarmStatus.Active);
        }

        public async Task<IEnumerable<Alarm>> GetAlarmsByDateRangeAsync(DateTime startDate, DateTime endDate)
        {
            return await _alarmRepository.GetByDateRangeAsync(startDate, endDate);
        }

        public async Task<bool> ResolveAlarmAsync(int alarmId, string resolutionNote)
        {
            var alarm = await _alarmRepository.GetByIdAsync(alarmId);
            if (alarm == null)
            {
                return false;
            }

            alarm.AlarmStatus = AlarmStatus.Resolved;
            alarm.ResolutionNote = resolutionNote;
            alarm.ResolvedTime = DateTime.Now;
            alarm.UpdateTime = DateTime.Now;

            return await _alarmRepository.UpdateAsync(alarm) != null;
        }

        public async Task<bool> AcknowledgeAlarmAsync(int alarmId, string acknowledgeNote)
        {
            var alarm = await _alarmRepository.GetByIdAsync(alarmId);
            if (alarm == null)
            {
                return false;
            }

            alarm.AlarmStatus = AlarmStatus.Acknowledged;
            alarm.AcknowledgeNote = acknowledgeNote;
            alarm.AcknowledgedTime = DateTime.Now;
            alarm.UpdateTime = DateTime.Now;

            return await _alarmRepository.UpdateAsync(alarm) != null;
        }

        public async Task<AlarmStatistics> GetAlarmStatisticsAsync(DateTime date)
        {
            return await _alarmRepository.GetAlarmStatisticsAsync(date);
        }

        public async Task<IEnumerable<Alarm>> GetCriticalAlarmsAsync()
        {
            return await _alarmRepository.GetBySeverityAsync(AlarmSeverity.Critical);
        }

        public async Task<IEnumerable<Alarm>> GetDeviceAlarmsAsync(int deviceId, int days = 7)
        {
            var startDate = DateTime.Now.AddDays(-days);
            var endDate = DateTime.Now;
            return await _alarmRepository.GetByDeviceAndDateRangeAsync(deviceId, startDate, endDate);
        }
    }

    public class AlarmRuleService : IAlarmRuleService
    {
        private readonly IAlarmRuleRepository _ruleRepository;
        private readonly IAlarmRepository _alarmRepository;
        private readonly IDeviceRepository _deviceRepository;
        private readonly ILoggerService _logger;

        public AlarmRuleService(
            IAlarmRuleRepository ruleRepository,
            IAlarmRepository alarmRepository,
            IDeviceRepository deviceRepository,
            ILoggerService logger)
        {
            _ruleRepository = ruleRepository;
            _alarmRepository = alarmRepository;
            _deviceRepository = deviceRepository;
            _logger = logger;
        }

        public async Task<AlarmRule> CreateAlarmRuleAsync(AlarmRule rule)
        {
            rule.IsActive = true;
            rule.CreateTime = DateTime.Now;
            rule.UpdateTime = DateTime.Now;
            
            return await _ruleRepository.AddAsync(rule);
        }

        public async Task<AlarmRule> UpdateAlarmRuleAsync(int ruleId, AlarmRule rule)
        {
            var existingRule = await _ruleRepository.GetByIdAsync(ruleId);
            if (existingRule == null)
            {
                throw new KeyNotFoundException($"Alarm rule with ID {ruleId} not found");
            }

            rule.RuleId = ruleId;
            rule.UpdateTime = DateTime.Now;
            
            return await _ruleRepository.UpdateAsync(rule);
        }

        public async Task<bool> DeleteAlarmRuleAsync(int ruleId)
        {
            return await _ruleRepository.DeleteAsync(ruleId);
        }

        public async Task<AlarmRule> GetAlarmRuleByIdAsync(int ruleId)
        {
            return await _ruleRepository.GetByIdAsync(ruleId);
        }

        public async Task<IEnumerable<AlarmRule>> GetAllAlarmRulesAsync()
        {
            return await _ruleRepository.GetAllAsync();
        }

        public async Task<IEnumerable<AlarmRule>> GetActiveAlarmRulesAsync()
        {
            return await _ruleRepository.GetByStatusAsync(true);
        }

        public async Task<IEnumerable<AlarmRule>> GetRulesByDeviceAsync(int deviceId)
        {
            return await _ruleRepository.GetByDeviceIdAsync(deviceId);
        }

        public async Task<bool> EvaluateAlarmRuleAsync(AlarmRule rule, DeviceCurrentStatus status)
        {
            if (!rule.IsActive || status == null)
                return false;

            try
            {
                switch (rule.RuleType)
                {
                    case AlarmRuleType.DeviceOffline:
                        return EvaluateDeviceOfflineRule(rule, status);
                    
                    case AlarmRuleType.TemperatureHigh:
                        return EvaluateTemperatureRule(rule, status);
                    
                    case AlarmRuleType.PressureHigh:
                        return EvaluatePressureRule(rule, status);
                    
                    case AlarmRuleType.ProductionStop:
                        return EvaluateProductionStopRule(rule, status);
                    
                    case AlarmRuleType.NetworkError:
                        return EvaluateNetworkErrorRule(rule, status);
                    
                    default:
                        return false;
                }
            }
            catch (Exception ex)
            {
                await _logger.LogErrorAsync($"Failed to evaluate alarm rule {rule.RuleId}: {ex.Message}");
                return false;
            }
        }

        public async Task<Alarm> GenerateAlarmFromRuleAsync(AlarmRule rule, DeviceCurrentStatus status)
        {
            var alarm = new Alarm
            {
                DeviceId = status.DeviceId,
                DeviceCode = "", // Will be populated from device
                AlarmType = rule.AlarmType,
                Severity = rule.Severity,
                Title = rule.AlarmTitle,
                Description = rule.AlarmDescription,
                AlarmStatus = AlarmStatus.Active,
                RuleId = rule.RuleId,
                CreateTime = DateTime.Now,
                UpdateTime = DateTime.Now
            };

            // Get device code
            var device = await _deviceRepository.GetByIdAsync(status.DeviceId);
            if (device != null)
            {
                alarm.DeviceCode = device.DeviceCode;
            }

            return alarm;
        }

        public async Task TestAlarmRuleAsync(int ruleId)
        {
            var rule = await _ruleRepository.GetByIdAsync(ruleId);
            if (rule == null)
                throw new KeyNotFoundException($"Alarm rule with ID {ruleId} not found");

            // Get a sample device status for testing
            var devices = await _deviceRepository.GetAllAsync();
            if (!devices.Any())
                throw new Exception("No devices available for testing");

            var sampleDevice = devices.First();
            var deviceStatus = new DeviceCurrentStatus
            {
                DeviceId = sampleDevice.Id,
                Status = "Running",
                IsRunning = true,
                NCProgram = "O1234",
                CumulativeCount = 1000,
                RecordTime = DateTime.Now
            };

            // Evaluate the rule
            var shouldTrigger = await EvaluateAlarmRuleAsync(rule, deviceStatus);
            
            if (shouldTrigger)
            {
                var alarm = await GenerateAlarmFromRuleAsync(rule, deviceStatus);
                alarm.Title = $"Test Alarm: {rule.AlarmTitle}";
                alarm.Description = $"This is a test alarm for rule '{rule.RuleName}'.";
                
                await _alarmRepository.AddAsync(alarm);
                await _alarmRepository.SaveAsync();
                
                await _logger.LogInformationAsync($"Test alarm created for rule {rule.RuleId}");
            }
            else
            {
                await _logger.LogInformationAsync($"Rule {rule.RuleId} did not trigger alarm during test");
            }
        }

        private bool EvaluateDeviceOfflineRule(AlarmRule rule, DeviceCurrentStatus status)
        {
            // Check if device status indicates offline
            return status.Status?.ToLower() == "offline" || 
                   !status.IsRunning ||
                   string.IsNullOrEmpty(status.NCProgram);
        }

        private bool EvaluateTemperatureRule(AlarmRule rule, DeviceCurrentStatus status)
        {
            // Find temperature tag
            var temperatureTag = status.Tags?.FirstOrDefault(t => t.Id?.Contains("temp") == true || t.Id?.Contains("温度") == true);
            if (temperatureTag == null || temperatureTag.Value == null)
                return false;

            if (decimal.TryParse(temperatureTag.Value.ToString(), out decimal temperature))
            {
                return temperature > rule.ThresholdValue;
            }

            return false;
        }

        private bool EvaluatePressureRule(AlarmRule rule, DeviceCurrentStatus status)
        {
            // Find pressure tag
            var pressureTag = status.Tags?.FirstOrDefault(t => t.Id?.Contains("pressure") == true || t.Id?.Contains("压力") == true);
            if (pressureTag == null || pressureTag.Value == null)
                return false;

            if (decimal.TryParse(pressureTag.Value.ToString(), out decimal pressure))
            {
                return pressure > rule.ThresholdValue;
            }

            return false;
        }

        private bool EvaluateProductionStopRule(AlarmRule rule, DeviceCurrentStatus status)
        {
            // Check if device has been stopped for specified duration
            var stopDuration = TimeSpan.FromMinutes(rule.ThresholdValue);
            return !status.IsRunning && 
                   status.RecordTime < DateTime.Now.Subtract(stopDuration);
        }

        private bool EvaluateNetworkErrorRule(AlarmRule rule, DeviceCurrentStatus status)
        {
            // Check for network-related errors in status
            return status.Tags?.Any(t => t.Id?.Contains("error") == true && t.Value?.ToString() == "1") == true;
        }
    }

    public class AlarmNotificationService : IAlarmNotificationService
    {
        private readonly IAlarmNotificationRepository _notificationRepository;
        private readonly IEmailService _emailService;
        private readonly ISmsService _smsService;
        private readonly IWechatService _wechatService;
        private readonly ILoggerService _logger;
        private readonly IDeviceRepository _deviceRepository;

        public AlarmNotificationService(
            IAlarmNotificationRepository notificationRepository,
            IEmailService emailService,
            ISmsService smsService,
            IWechatService wechatService,
            ILoggerService logger,
            IDeviceRepository deviceRepository)
        {
            _notificationRepository = notificationRepository;
            _emailService = emailService;
            _smsService = smsService;
            _wechatService = wechatService;
            _logger = logger;
            _deviceRepository = deviceRepository;
        }

        public async Task SendAlarmNotificationAsync(Alarm alarm)
        {
            try
            {
                var device = await _deviceRepository.GetByIdAsync(alarm.DeviceId);
                var notificationChannels = await GetNotificationChannelsForDevice(alarm.DeviceId);

                foreach (var channel in notificationChannels)
                {
                    if (channel.IsEnabled)
                    {
                        await SendNotificationViaChannel(alarm, channel, device);
                    }
                }

                // Log the notification
                await LogNotificationSent(alarm, notificationChannels.Count());
            }
            catch (Exception ex)
            {
                await _logger.LogErrorAsync($"Failed to send alarm notification for alarm {alarm.AlarmId}: {ex.Message}");
            }
        }

        public async Task SendBulkAlarmNotificationsAsync(IEnumerable<Alarm> alarms)
        {
            foreach (var alarm in alarms)
            {
                await SendAlarmNotificationAsync(alarm);
            }
        }

        public async Task<bool> SendSmsNotificationAsync(string phoneNumber, string message)
        {
            try
            {
                return await _smsService.SendSmsAsync(phoneNumber, message);
            }
            catch (Exception ex)
            {
                await _logger.LogErrorAsync($"Failed to send SMS to {phoneNumber}: {ex.Message}");
                return false;
            }
        }

        public async Task<bool> SendEmailNotificationAsync(string email, string subject, string message)
        {
            try
            {
                return await _emailService.SendEmailAsync(email, subject, message);
            }
            catch (Exception ex)
            {
                await _logger.LogErrorAsync($"Failed to send email to {email}: {ex.Message}");
                return false;
            }
        }

        public async Task<bool> SendWechatNotificationAsync(string openId, string message)
        {
            try
            {
                return await _wechatService.SendMessageAsync(openId, message);
            }
            catch (Exception ex)
            {
                await _logger.LogErrorAsync($"Failed to send WeChat message to {openId}: {ex.Message}");
                return false;
            }
        }

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

        public async Task<bool> ConfigureNotificationChannelAsync(NotificationChannel channel)
        {
            // Validate channel configuration
            if (!ValidateChannelConfiguration(channel))
                return false;

            // Save channel configuration
            return await _notificationRepository.SaveChannelAsync(channel);
        }

        public async Task<IEnumerable<NotificationChannel>> GetAvailableChannelsAsync()
        {
            return await _notificationRepository.GetAllChannelsAsync();
        }

        private async Task<List<NotificationChannel>> GetNotificationChannelsForDevice(int deviceId)
        {
            // This would typically query the database for device-specific notification settings
            // For now, return a default set of channels
            return new List<NotificationChannel>
            {
                new NotificationChannel { ChannelType = NotificationChannelType.Email, IsEnabled = true },
                new NotificationChannel { ChannelType = NotificationChannelType.Sms, IsEnabled = false },
                new NotificationChannel { ChannelType = NotificationChannelType.WeChat, IsEnabled = false }
            };
        }

        private async Task SendNotificationViaChannel(Alarm alarm, NotificationChannel channel, Device device)
        {
            var message = FormatAlarmMessage(alarm, device);
            var subject = $"Alarm: {alarm.AlarmType} - {device?.DeviceCode}";

            switch (channel.ChannelType)
            {
                case NotificationChannelType.Email:
                    if (!string.IsNullOrEmpty(channel.Recipient))
                    {
                        await SendEmailNotificationAsync(channel.Recipient, subject, message);
                    }
                    break;
                
                case NotificationChannelType.Sms:
                    if (!string.IsNullOrEmpty(channel.Recipient))
                    {
                        await SendSmsNotificationAsync(channel.Recipient, message);
                    }
                    break;
                
                case NotificationChannelType.WeChat:
                    if (!string.IsNullOrEmpty(channel.Recipient))
                    {
                        await SendWechatNotificationAsync(channel.Recipient, message);
                    }
                    break;
            }
        }

        private string FormatAlarmMessage(Alarm alarm, Device device)
        {
            return $"🚨 Alarm Alert\n\n" +
                   $"Device: {device?.DeviceCode} ({device?.DeviceName})\n" +
                   $"Type: {alarm.AlarmType}\n" +
                   $"Severity: {alarm.Severity}\n" +
                   $"Title: {alarm.Title}\n" +
                   $"Description: {alarm.Description}\n" +
                   $"Time: {alarm.CreateTime:yyyy-MM-dd HH:mm:ss}\n" +
                   $"Device ID: {alarm.DeviceId}";
        }

        private bool ValidateChannelConfiguration(NotificationChannel channel)
        {
            switch (channel.ChannelType)
            {
                case NotificationChannelType.Email:
                    return !string.IsNullOrEmpty(channel.Recipient) && channel.Recipient.Contains("@");
                
                case NotificationChannelType.Sms:
                    return !string.IsNullOrEmpty(channel.Recipient) && channel.Recipient.All(char.IsDigit);
                
                case NotificationChannelType.WeChat:
                    return !string.IsNullOrEmpty(channel.Recipient);
                
                default:
                    return false;
            }
        }

        private async Task LogNotificationSent(Alarm alarm, int channelCount)
        {
            var notification = new AlarmNotification
            {
                AlarmId = alarm.AlarmId,
                NotificationTime = DateTime.Now,
                ChannelsUsed = channelCount,
                Success = true
            };

            await _notificationRepository.AddNotificationAsync(notification);
        }
    }

    // Additional supporting classes and interfaces
    public interface IEmailService
    {
        Task<bool> SendEmailAsync(string email, string subject, string message);
    }

    public interface ISmsService
    {
        Task<bool> SendSmsAsync(string phoneNumber, string message);
    }

    public interface IWechatService
    {
        Task<bool> SendMessageAsync(string openId, string message);
    }

    public interface IAlarmRuleRepository
    {
        Task<AlarmRule> AddAsync(AlarmRule rule);
        Task<AlarmRule> UpdateAsync(AlarmRule rule);
        Task<bool> DeleteAsync(int ruleId);
        Task<AlarmRule> GetByIdAsync(int ruleId);
        Task<IEnumerable<AlarmRule>> GetAllAsync();
        Task<IEnumerable<AlarmRule>> GetByStatusAsync(bool isActive);
        Task<IEnumerable<AlarmRule>> GetByDeviceIdAsync(int deviceId);
    }

    public interface IAlarmNotificationRepository
    {
        Task<AlarmNotification> AddNotificationAsync(AlarmNotification notification);
        Task<IEnumerable<AlarmNotification>> GetByDateRangeAsync(DateTime startDate, DateTime endDate);
        Task<bool> SaveChannelAsync(NotificationChannel channel);
        Task<IEnumerable<NotificationChannel>> GetAllChannelsAsync();
    }
}