using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Haoliang.Models.System;

namespace Haoliang.Core.Services
{
    public interface IRulesService
    {
        /// <summary>
        /// Get all business rules
        /// </summary>
        Task<List<BusinessRuleConfig>> GetAllRulesAsync();

        /// <summary>
        /// Create or update business rule
        /// </summary>
        Task<BusinessRuleConfig> CreateOrUpdateRuleAsync(BusinessRuleConfig rule);

        /// <summary>
        /// Delete business rule
        /// </summary>
        Task<bool> DeleteRuleAsync(int ruleId);

        /// <summary>
        /// Get statistics rules
        /// </summary>
        Task<List<StatisticsRuleConfig>> GetStatisticsRulesAsync();

        /// <summary>
        /// Update statistics rules
        /// </summary>
        Task<bool> UpdateStatisticsRulesAsync(List<StatisticsRuleConfig> rules);

        /// <summary>
        /// Validate business rule expression
        /// </summary>
        Task<RuleValidationResult> ValidateRuleAsync(BusinessRuleConfig rule);

        /// <summary>
        /// Evaluate business rule against data
        /// </summary>
        Task<RuleEvaluationResult> EvaluateRuleAsync(BusinessRuleConfig rule, object data);

        /// <summary>
        /// Get rule execution history
        /// </summary>
        Task<List<RuleExecutionHistory>> GetRuleExecutionHistoryAsync(int ruleId, DateTime? startDate = null, DateTime? endDate = null);
    }

    public class RulesService : IRulesService
    {
        private readonly ISystemRepository _systemRepository;
        private readonly IProductionRepository _productionRepository;
        private readonly IAlarmRepository _alarmRepository;
        private readonly ICacheService _cacheService;

        public RulesService(
            ISystemRepository systemRepository,
            IProductionRepository productionRepository,
            IAlarmRepository alarmRepository,
            ICacheService cacheService)
        {
            _systemRepository = systemRepository;
            _productionRepository = productionRepository;
            _alarmRepository = alarmRepository;
            _cacheService = cacheService;
        }

        public async Task<List<BusinessRuleConfig>> GetAllRulesAsync()
        {
            return await _cacheService.GetOrSetAllRulesAsync(() =>
                _systemRepository.GetAllBusinessRulesAsync());
        }

        public async Task<BusinessRuleConfig> CreateOrUpdateRuleAsync(BusinessRuleConfig rule)
        {
            // Validate rule before saving
            var validationResult = await ValidateRuleAsync(rule);
            if (!validationResult.IsValid)
            {
                throw new ArgumentException($"Invalid rule: {validationResult.ErrorMessage}");
            }

            // Save rule to repository
            var savedRule = await _systemRepository.SaveBusinessRuleAsync(rule);

            // Clear cache
            _cacheService.InvalidateRulesCache();

            return savedRule;
        }

        public async Task<bool> DeleteRuleAsync(int ruleId)
        {
            var result = await _systemRepository.DeleteBusinessRuleAsync(ruleId);
            
            if (result)
            {
                _cacheService.InvalidateRulesCache();
            }

            return result;
        }

        public async Task<List<StatisticsRuleConfig>> GetStatisticsRulesAsync()
        {
            return await _cacheService.GetOrSetAllStatisticsRulesAsync(() =>
                _systemRepository.GetAllStatisticsRulesAsync());
        }

        public async Task<bool> UpdateStatisticsRulesAsync(List<StatisticsRuleConfig> rules)
        {
            // Validate all rules
            foreach (var rule in rules)
            {
                var validationResult = await ValidateStatisticsRuleAsync(rule);
                if (!validationResult.IsValid)
                {
                    throw new ArgumentException($"Invalid statistics rule: {validationResult.ErrorMessage}");
                }
            }

            // Save all rules
            var result = await _systemRepository.SaveStatisticsRulesAsync(rules);

            if (result)
            {
                _cacheService.InvalidateRulesCache();
            }

            return result;
        }

        public async Task<RuleValidationResult> ValidateRuleAsync(BusinessRuleConfig rule)
        {
            var result = new RuleValidationResult { IsValid = true };

            if (rule == null)
            {
                result.IsValid = false;
                result.ErrorMessage = "Rule cannot be null";
                return result;
            }

            if (string.IsNullOrWhiteSpace(rule.RuleName))
            {
                result.IsValid = false;
                result.ErrorMessage = "Rule name cannot be empty";
                return result;
            }

            if (string.IsNullOrWhiteSpace(rule.RuleExpression))
            {
                result.IsValid = false;
                result.ErrorMessage = "Rule expression cannot be empty";
                return result;
            }

            // Validate rule syntax
            if (!IsValidRuleExpression(rule.RuleExpression))
            {
                result.IsValid = false;
                result.ErrorMessage = "Invalid rule expression syntax";
                return result;
            }

            // Test rule with sample data
            try
            {
                var sampleData = GetSampleDataForRule(rule);
                var testResult = await EvaluateRuleAsync(rule, sampleData);
                
                if (!testResult.Success)
                {
                    result.IsValid = false;
                    result.ErrorMessage = $"Rule evaluation failed: {testResult.ErrorMessage}";
                }
            }
            catch (Exception ex)
            {
                result.IsValid = false;
                result.ErrorMessage = $"Rule validation error: {ex.Message}";
            }

            return result;
        }

        public async Task<RuleEvaluationResult> EvaluateRuleAsync(BusinessRuleConfig rule, object data)
        {
            var result = new RuleEvaluationResult { Success = true };

            try
            {
                // Parse and evaluate the rule expression
                var evaluator = new RuleExpressionEvaluator();
                var evaluationResult = evaluator.Evaluate(rule.RuleExpression, data);

                result.Success = evaluationResult.Success;
                result.Result = evaluationResult.Result;
                result.EvaluationTime = evaluationResult.EvaluationTime;
                result.ErrorMessage = evaluationResult.ErrorMessage;

                // Log rule execution if successful
                if (result.Success && rule.Enabled)
                {
                    await LogRuleExecutionAsync(rule, data, result);
                }
            }
            catch (Exception ex)
            {
                result.Success = false;
                result.ErrorMessage = ex.Message;
            }

            return result;
        }

        public async Task<List<RuleExecutionHistory>> GetRuleExecutionHistoryAsync(int ruleId, DateTime? startDate = null, DateTime? endDate = null)
        {
            return await _systemRepository.GetRuleExecutionHistoryAsync(ruleId, startDate, endDate);
        }

        #region Private Methods

        private bool IsValidRuleExpression(string expression)
        {
            // Basic validation - in a real implementation, you would use a proper expression parser
            return !string.IsNullOrWhiteSpace(expression) && 
                   !expression.Contains("DELETE") && 
                   !expression.Contains("DROP") &&
                   !expression.Contains("TRUNCATE");
        }

        private object GetSampleDataForRule(BusinessRuleConfig rule)
        {
            // Return sample data based on rule type
            return new
            {
                Production = new { Quantity = 100, Target = 120, Quality = 95 },
                Device = new { Status = "Running", Efficiency = 85 },
                Time = DateTime.Now
            };
        }

        private async Task ValidateStatisticsRuleAsync(StatisticsRuleConfig rule)
        {
            // Implementation for validating statistics rules
            if (string.IsNullOrWhiteSpace(rule.RuleName))
            {
                throw new ArgumentException("Statistics rule name cannot be empty");
            }

            if (string.IsNullOrWhiteSpace(rule.CalculationExpression))
            {
                throw new ArgumentException("Statistics rule calculation expression cannot be empty");
            }
        }

        private async Task LogRuleExecutionAsync(BusinessRuleConfig rule, object data, RuleEvaluationResult result)
        {
            var execution = new RuleExecutionHistory
            {
                RuleId = rule.RuleId,
                RuleName = rule.RuleName,
                InputDataJson = System.Text.Json.JsonSerializer.Serialize(data),
                Result = result.Result?.ToString(),
                Success = result.Success,
                ErrorMessage = result.ErrorMessage,
                ExecutionTime = DateTime.UtcNow
            };

            await _systemRepository.LogRuleExecutionAsync(execution);
        }

        #endregion
    }

    #region Supporting Classes

    public class RuleExpressionEvaluator
    {
        public RuleEvaluationResult Evaluate(string expression, object data)
        {
            var result = new RuleEvaluationResult();
            var startTime = DateTime.UtcNow;

            try
        {
                // Parse the expression and evaluate against data
                // This is a simplified implementation
                // In a real scenario, you would use a proper expression parser or scripting engine
                
                var parser = new ExpressionParser();
                var evaluationResult = parser.ParseAndEvaluate(expression, data);

                result.Success = evaluationResult.Success;
                result.Result = evaluationResult.Value;
                result.ErrorMessage = evaluationResult.Error;
            }
            catch (Exception ex)
            {
                result.Success = false;
                result.ErrorMessage = ex.Message;
            }

            result.EvaluationTime = DateTime.UtcNow - startTime;
            return result;
        }
    }

    public class ExpressionParser
    {
        public ParseResult ParseAndEvaluate(string expression, object data)
        {
            var result = new ParseResult();

            try
            {
                // Simple expression evaluation
                // In a real implementation, you would use a proper expression parser
                // like NCalc, System.Linq.Dynamic.Core, or a custom parser
                
                if (expression.Contains(">"))
                {
                    var parts = expression.Split('>');
                    if (parts.Length == 2)
                    {
                        var left = EvaluateExpression(parts[0].Trim(), data);
                        var right = EvaluateExpression(parts[1].Trim(), data);
                        
                        if (left != null && right != null)
                        {
                            result.Value = Convert.ToDecimal(left) > Convert.ToDecimal(right);
                        }
                    }
                }
                else if (expression.Contains("<"))
                {
                    var parts = expression.Split('<');
                    if (parts.Length == 2)
                    {
                        var left = EvaluateExpression(parts[0].Trim(), data);
                        var right = EvaluateExpression(parts[1].Trim(), data);
                        
                        if (left != null && right != null)
                        {
                            result.Value = Convert.ToDecimal(left) < Convert.ToDecimal(right);
                        }
                    }
                }
                else if (expression.Contains("="))
                {
                    var parts = expression.Split('=');
                    if (parts.Length == 2)
                    {
                        var left = EvaluateExpression(parts[0].Trim(), data);
                        var right = EvaluateExpression(parts[1].Trim(), data);
                        
                        if (left != null && right != null)
                        {
                            result.Value = left.ToString() == right.ToString();
                        }
                    }
                }
                else
                {
                    // Simple value evaluation
                    result.Value = EvaluateExpression(expression, data);
                }

                result.Success = true;
            }
            catch (Exception ex)
            {
                result.Success = false;
                result.Error = ex.Message;
            }

            return result;
        }

        private object EvaluateExpression(string expression, object data)
        {
            // Simple property extraction from data object
            // In a real implementation, this would be more sophisticated
            
            if (data is null)
                return null;

            // Handle simple property access
            if (expression.Contains("."))
            {
                var parts = expression.Split('.');
                if (parts.Length == 2)
                {
                    var property = parts[1];
                    var dataDict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(
                        System.Text.Json.JsonSerializer.Serialize(data));

                    return dataDict?.TryGetValue(property, out var value) == true ? value : null;
                }
            }

            // Handle simple numeric comparison
            if (decimal.TryParse(expression, out var numericValue))
            {
                return numericValue;
            }

            return null;
        }
    }

    public class ParseResult
    {
        public bool Success { get; set; }
        public object Value { get; set; }
        public string Error { get; set; }
    }

    public class RuleEvaluationResult
    {
        public bool Success { get; set; }
        public object Result { get; set; }
        public TimeSpan EvaluationTime { get; set; }
        public string ErrorMessage { get; set; }
    }

    public class RuleValidationResult
    {
        public bool IsValid { get; set; }
        public string ErrorMessage { get; set; }
        public List<string> Warnings { get; set; } = new List<string>();
    }

    #endregion
}