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;

namespace Haoliang.Core.Services
{
    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 class AlarmRuleService : IAlarmRuleService
    {
        private readonly IAlarmRuleRepository _alarmRuleRepository;
        private readonly IDeviceRepository _deviceRepository;
        private readonly IAlarmRepository _alarmRepository;
        private readonly ILoggingService _loggingService;

        public AlarmRuleService(
            IAlarmRuleRepository alarmRuleRepository,
            IDeviceRepository deviceRepository,
            IAlarmRepository alarmRepository,
            ILoggingService loggingService)
        {
            _alarmRuleRepository = alarmRuleRepository;
            _deviceRepository = deviceRepository;
            _alarmRepository = alarmRepository;
            _loggingService = loggingService;
        }

        public async Task<AlarmRule> CreateAlarmRuleAsync(AlarmRule rule)
        {
            // Validate rule
            if (string.IsNullOrWhiteSpace(rule.RuleName))
                throw new ArgumentException("Rule name is required");

            if (string.IsNullOrWhiteSpace(rule.Condition))
                throw new ArgumentException("Condition is required");

            rule.RuleId = 0; // Ensure new rule
            rule.CreatedAt = DateTime.Now;
            rule.UpdatedAt = DateTime.Now;

            await _alarmRuleRepository.AddAsync(rule);
            await _alarmRuleRepository.SaveAsync();

            await _loggingService.LogInfoAsync($"Created alarm rule: {rule.RuleName}");
            return rule;
        }

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

            existingRule.RuleName = rule.RuleName;
            existingRule.Condition = rule.Condition;
            existingRule.AlarmType = rule.AlarmType;
            existingRule.AlarmSeverity = rule.AlarmSeverity;
            existingRule.IsActive = rule.IsActive;
            existingRule.DeviceId = rule.DeviceId;
            existingRule.UpdatedAt = DateTime.Now;

            await _alarmRuleRepository.UpdateAsync(existingRule);
            await _alarmRuleRepository.SaveAsync();

            await _loggingService.LogInfoAsync($"Updated alarm rule: {existingRule.RuleName}");
            return existingRule;
        }

        public async Task<bool> DeleteAlarmRuleAsync(int ruleId)
        {
            var rule = await _alarmRuleRepository.GetByIdAsync(ruleId);
            if (rule == null)
                return false;

            await _alarmRuleRepository.DeleteAsync(rule);
            await _alarmRuleRepository.SaveAsync();

            await _loggingService.LogInfoAsync($"Deleted alarm rule: {rule.RuleName}");
            return true;
        }

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

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

        public async Task<IEnumerable<AlarmRule>> GetActiveAlarmRulesAsync()
        {
            return await _alarmRuleRepository.GetActiveRulesAsync();
        }

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

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

            try
            {
                // Simple condition evaluation (in real implementation, use expression parser)
                var condition = rule.Condition.ToLower();
                
                if (condition.Contains("device_offline") && !status.IsOnline)
                    return true;
                
                if (condition.Contains("device_error") && status.Status == "Error")
                    return true;
                
                if (condition.Contains("high_temperature") && 
                    status.Tags?.Any(t => t.Id == "temperature" && Convert.ToDouble(t.Value) > 80) == true)
                    return true;
                
                if (condition.Contains("low_production") && 
                    status.CumulativeCount < 10)
                    return true;

                // Custom condition evaluation
                if (condition.Contains("running_time") && 
                    status.IsRunning && 
                    (DateTime.Now - status.RecordTime).TotalMinutes > 120)
                    return true;

                return false;
            }
            catch (Exception ex)
            {
                await _loggingService.LogErrorAsync($"Error evaluating alarm rule {rule.RuleName}: {ex.Message}", ex);
                return false;
            }
        }

        public async Task<Alarm> GenerateAlarmFromRuleAsync(AlarmRule rule, DeviceCurrentStatus status)
        {
            var device = await _deviceRepository.GetByIdAsync(status.DeviceId);
            if (device == null)
                throw new InvalidOperationException("Device not found");

            var alarm = new Alarm
            {
                DeviceId = status.DeviceId,
                DeviceCode = device.DeviceCode,
                DeviceName = device.DeviceName,
                AlarmType = rule.AlarmType.ToString(),
                AlarmSeverity = rule.AlarmSeverity,
                Title = $"Alarm triggered by rule: {rule.RuleName}",
                Description = $"Condition: {rule.Condition}",
                AlarmStatus = AlarmStatus.Active,
                CreateTime = DateTime.Now,
                IsActive = true
            };

            await _alarmRepository.AddAsync(alarm);
            await _alarmRepository.SaveAsync();

            await _loggingService.LogWarningAsync($"Generated alarm: {alarm.Title} for device {device.DeviceCode}");
            return alarm;
        }

        public async Task TestAlarmRuleAsync(int ruleId)
        {
            var rule = await _alarmRuleRepository.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();
            var sampleDevice = devices.FirstOrDefault();
            
            if (sampleDevice == null)
            {
                await _loggingService.LogWarningAsync($"No devices available to test alarm rule {rule.RuleName}");
                return;
            }

            var sampleStatus = new DeviceCurrentStatus
            {
                DeviceId = sampleDevice.Id,
                DeviceCode = sampleDevice.DeviceCode,
                DeviceName = sampleDevice.DeviceName,
                IsOnline = true,
                IsAvailable = true,
                Status = "Running",
                IsRunning = true,
                NCProgram = "TEST_PROGRAM",
                CumulativeCount = 50,
                OperatingMode = "Auto",
                RecordTime = DateTime.Now,
                Tags = new List<TagData>
                {
                    new TagData { Id = "temperature", Value = 85.0, Time = DateTime.Now },
                    new TagData { Id = "pressure", Value = 120, Time = DateTime.Now }
                }
            };

            var shouldTrigger = await EvaluateAlarmRuleAsync(rule, sampleStatus);
            
            if (shouldTrigger)
            {
                await GenerateAlarmFromRuleAsync(rule, sampleStatus);
                await _loggingService.LogInformationAsync($"Alarm rule test: {rule.RuleName} would trigger an alarm");
            }
            else
            {
                await _loggingService.LogInformationAsync($"Alarm rule test: {rule.RuleName} would not trigger an alarm");
            }
        }
    }

    // Additional repository interface for alarm rules
    public interface IAlarmRuleRepository : IRepository<AlarmRule>
    {
        Task<IEnumerable<AlarmRule>> GetActiveRulesAsync();
        Task<IEnumerable<AlarmRule>> GetRulesByDeviceAsync(int deviceId);
        Task<IEnumerable<AlarmRule>> GetRulesByAlarmTypeAsync(AlarmType alarmType);
        Task<bool> RuleExistsAsync(string ruleName);
        Task<IEnumerable<AlarmRule>> GetEnabledRulesAsync();
    }
}