using System.Text.RegularExpressions;
using MktZaloService.Domain.Enums;
using MktZaloService.Domain.Events;
using MktZaloService.Domain.Exceptions;
using MktZaloService.Domain.SeedWork;

namespace MktZaloService.Domain.AggregatesModel.ChatbotRuleAggregate;

/// <summary>
/// EN: Entity representing a single condition in a chatbot rule.
/// VI: Entity đại diện cho một điều kiện trong quy tắc chatbot.
/// </summary>
public class ChatbotRuleCondition : Entity
{
    /// <summary>
    /// EN: Field to evaluate.
    /// VI: Trường để đánh giá.
    /// </summary>
    public string Field { get; private set; } = string.Empty;

    /// <summary>
    /// EN: Comparison operator.
    /// VI: Toán tử so sánh.
    /// </summary>
    public string Operator { get; private set; } = string.Empty;

    /// <summary>
    /// EN: Value to compare against.
    /// VI: Giá trị để so sánh.
    /// </summary>
    public string Value { get; private set; } = string.Empty;

    /// <summary>
    /// EN: ID of parent rule.
    /// VI: ID quy tắc cha.
    /// </summary>
    public Guid RuleId { get; private set; }

    /// <summary>
    /// EN: Navigation property to parent rule.
    /// VI: Navigation property đến quy tắc cha.
    /// </summary>
    public ChatbotRule Rule { get; private set; } = null!;

    /// <summary>
    /// EN: When this condition was created.
    /// VI: Thời điểm điều kiện này được tạo.
    /// </summary>
    public DateTime CreatedAt { get; private set; }

    protected ChatbotRuleCondition() { }

    public ChatbotRuleCondition(string field, string @operator, string value)
    {
        Id = Guid.NewGuid();
        Field = field ?? throw new ArgumentNullException(nameof(field));
        Operator = @operator ?? throw new ArgumentNullException(nameof(@operator));
        Value = value ?? throw new ArgumentNullException(nameof(value));
        CreatedAt = DateTime.UtcNow;
    }
}

/// <summary>
/// EN: Aggregate root for managing chatbot automation rules.
/// VI: Aggregate root để quản lý quy tắc tự động hóa chatbot.
/// </summary>
public class ChatbotRule : Entity, IAggregateRoot
{
    private readonly List<ChatbotRuleCondition> _conditions = new();

    /// <summary>
    /// EN: Name of the rule.
    /// VI: Tên của quy tắc.
    /// </summary>
    public string Name { get; private set; } = string.Empty;

    /// <summary>
    /// EN: Description of what this rule does.
    /// VI: Mô tả quy tắc này làm gì.
    /// </summary>
    public string? Description { get; private set; }

    /// <summary>
    /// EN: Type of rule matching (keyword, regex, intent).
    /// VI: Loại khớp quy tắc (từ khóa, regex, ý định).
    /// </summary>
    public RuleType Type { get; private set; }

    /// <summary>
    /// EN: Rule conditions.
    /// VI: Các điều kiện quy tắc.
    /// </summary>
    public IReadOnlyCollection<ChatbotRuleCondition> Conditions => _conditions.AsReadOnly();

    /// <summary>
    /// EN: Action to take when rule matches.
    /// VI: Hành động khi quy tắc khớp.
    /// </summary>
    public RuleAction Action { get; private set; } = null!;

    /// <summary>
    /// EN: Priority (0-100, higher = evaluated first).
    /// VI: Độ ưu tiên (0-100, cao hơn = đánh giá trước).
    /// </summary>
    public int Priority { get; private set; }

    /// <summary>
    /// EN: Whether the rule is active.
    /// VI: Quy tắc có đang hoạt động không.
    /// </summary>
    public bool IsActive { get; private set; }

    /// <summary>
    /// EN: Number of times this rule has matched.
    /// VI: Số lần quy tắc này đã khớp.
    /// </summary>
    public int MatchCount { get; private set; }

    /// <summary>
    /// EN: Last time this rule matched.
    /// VI: Lần cuối quy tắc này khớp.
    /// </summary>
    public DateTime? LastMatchedAt { get; private set; }

    /// <summary>
    /// EN: Audit field: Created timestamp.
    /// VI: Trường audit: Thời điểm tạo.
    /// </summary>
    public DateTime CreatedAt { get; private set; }

    /// <summary>
    /// EN: Audit field: Last updated timestamp.
    /// VI: Trường audit: Thời điểm cập nhật cuối.
    /// </summary>
    public DateTime UpdatedAt { get; private set; }

    protected ChatbotRule() { }

    /// <summary>
    /// EN: Create a new chatbot rule.
    /// VI: Tạo quy tắc chatbot mới.
    /// </summary>
    public ChatbotRule(
        string name,
        RuleType type,
        RuleAction action,
        int priority = 50,
        string? description = null)
    {
        if (priority < 0 || priority > 100)
        {
            throw new ArgumentOutOfRangeException(nameof(priority), "Priority must be between 0 and 100");
        }

        Id = Guid.NewGuid();
        Name = name ?? throw new ArgumentNullException(nameof(name));
        Description = description;
        Type = type;
        Action = action ?? throw new ArgumentNullException(nameof(action));
        Priority = priority;
        IsActive = true;
        MatchCount = 0;
        CreatedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Add a condition to the rule.
    /// VI: Thêm điều kiện vào quy tắc.
    /// </summary>
    public void AddCondition(string field, string @operator, string value)
    {
        _conditions.Add(new ChatbotRuleCondition(field, @operator, value));
        UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Clear all conditions.
    /// VI: Xóa tất cả điều kiện.
    /// </summary>
    public void ClearConditions()
    {
        _conditions.Clear();
        UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Evaluate if the rule matches the user message.
    /// VI: Đánh giá nếu quy tắc khớp với tin nhắn người dùng.
    /// </summary>
    public bool Evaluate(string userMessage)
    {
        if (!IsActive || _conditions.Count == 0)
        {
            return false;
        }

        return Type switch
        {
            RuleType.Keyword => EvaluateKeyword(userMessage),
            RuleType.Regex => EvaluateRegex(userMessage),
            RuleType.Intent => false, // Intent handled by AI engine
            _ => false
        };
    }

    private bool EvaluateKeyword(string message)
    {
        // Any condition matches = rule matches
        return _conditions.Any(c =>
            c.Operator.Equals("contains", StringComparison.OrdinalIgnoreCase) &&
            message.Contains(c.Value, StringComparison.OrdinalIgnoreCase));
    }

    private bool EvaluateRegex(string message)
    {
        try
        {
            return _conditions.Any(c =>
                Regex.IsMatch(message, c.Value, RegexOptions.IgnoreCase, TimeSpan.FromSeconds(1)));
        }
        catch (RegexMatchTimeoutException)
        {
            return false;
        }
    }

    /// <summary>
    /// EN: Record that this rule matched a message.
    /// VI: Ghi nhận quy tắc này đã khớp với tin nhắn.
    /// </summary>
    public void RecordMatch(Guid conversationId, string matchedMessage)
    {
        MatchCount++;
        LastMatchedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;

        AddDomainEvent(new ChatbotRuleMatchedDomainEvent(Id, conversationId, matchedMessage));
    }

    /// <summary>
    /// EN: Activate the rule.
    /// VI: Kích hoạt quy tắc.
    /// </summary>
    public void Activate()
    {
        IsActive = true;
        UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Deactivate the rule.
    /// VI: Hủy kích hoạt quy tắc.
    /// </summary>
    public void Deactivate()
    {
        IsActive = false;
        UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update rule details.
    /// VI: Cập nhật chi tiết quy tắc.
    /// </summary>
    public void Update(string name, RuleType type, RuleAction action, int priority, string? description = null)
    {
        if (priority < 0 || priority > 100)
        {
            throw new ArgumentOutOfRangeException(nameof(priority), "Priority must be between 0 and 100");
        }

        Name = name ?? throw new ArgumentNullException(nameof(name));
        Description = description;
        Type = type;
        Action = action ?? throw new ArgumentNullException(nameof(action));
        Priority = priority;
        UpdatedAt = DateTime.UtcNow;
    }
}
