using MktZaloService.Domain.Enums;
using MktZaloService.Domain.Exceptions;
using MktZaloService.Domain.SeedWork;

namespace MktZaloService.Domain.AggregatesModel.TemplateAggregate;

/// <summary>
/// EN: Entity representing a template parameter.
/// VI: Entity đại diện cho tham số mẫu.
/// </summary>
public class TemplateParameter : Entity
{
    /// <summary>
    /// EN: Name of the parameter.
    /// VI: Tên của tham số.
    /// </summary>
    public string Name { get; private set; } = string.Empty;

    /// <summary>
    /// EN: Whether this parameter is required.
    /// VI: Tham số này có bắt buộc không.
    /// </summary>
    public bool IsRequired { get; private set; }

    /// <summary>
    /// EN: Default value if not provided.
    /// VI: Giá trị mặc định nếu không cung cấp.
    /// </summary>
    public string? DefaultValue { get; private set; }

    /// <summary>
    /// EN: ID of parent template.
    /// VI: ID mẫu cha.
    /// </summary>
    public Guid TemplateId { get; private set; }

    /// <summary>
    /// EN: Navigation property to parent template.
    /// VI: Navigation property đến mẫu cha.
    /// </summary>
    public MessageTemplate Template { get; private set; } = null!;

    protected TemplateParameter() { }

    public TemplateParameter(string name, bool isRequired = true, string? defaultValue = null)
    {
        Id = Guid.NewGuid();
        Name = name ?? throw new ArgumentNullException(nameof(name));
        IsRequired = isRequired;
        DefaultValue = defaultValue;
    }
}

/// <summary>
/// EN: Aggregate root for managing ZNS message templates.
/// VI: Aggregate root để quản lý mẫu tin nhắn ZNS.
/// </summary>
public class MessageTemplate : Entity, IAggregateRoot
{
    private readonly List<TemplateParameter> _parameters = new();

    /// <summary>
    /// EN: Zalo's template ID.
    /// VI: ID mẫu của Zalo.
    /// </summary>
    public string ZaloTemplateId { get; private set; } = string.Empty;

    /// <summary>
    /// EN: Name of the template.
    /// VI: Tên của mẫu.
    /// </summary>
    public string Name { get; private set; } = string.Empty;

    /// <summary>
    /// EN: Template content/body.
    /// VI: Nội dung mẫu.
    /// </summary>
    public string Content { get; private set; } = string.Empty;

    /// <summary>
    /// EN: Template approval status.
    /// VI: Trạng thái phê duyệt mẫu.
    /// </summary>
    public TemplateStatus Status { get; private set; }

    /// <summary>
    /// EN: Template parameters.
    /// VI: Các tham số mẫu.
    /// </summary>
    public IReadOnlyCollection<TemplateParameter> Parameters => _parameters.AsReadOnly();

    /// <summary>
    /// EN: Number of times this template has been sent.
    /// VI: Số lần mẫu này đã được gửi.
    /// </summary>
    public int SendCount { 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 MessageTemplate() { }

    /// <summary>
    /// EN: Create a new message template.
    /// VI: Tạo mẫu tin nhắn mới.
    /// </summary>
    public MessageTemplate(string zaloTemplateId, string name, string content)
    {
        Id = Guid.NewGuid();
        ZaloTemplateId = zaloTemplateId ?? throw new ArgumentNullException(nameof(zaloTemplateId));
        Name = name ?? throw new ArgumentNullException(nameof(name));
        Content = content ?? throw new ArgumentNullException(nameof(content));
        Status = TemplateStatus.Pending;
        SendCount = 0;
        CreatedAt = DateTime.UtcNow;
        UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Add a parameter to the template.
    /// VI: Thêm tham số vào mẫu.
    /// </summary>
    public void AddParameter(string name, bool isRequired = true, string? defaultValue = null)
    {
        if (_parameters.Any(p => p.Name.Equals(name, StringComparison.OrdinalIgnoreCase)))
        {
            throw new ZaloDomainException($"Parameter '{name}' already exists in template");
        }

        _parameters.Add(new TemplateParameter(name, isRequired, defaultValue));
        UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Validate that all required parameters are provided.
    /// VI: Xác thực rằng tất cả tham số bắt buộc đã được cung cấp.
    /// </summary>
    public Dictionary<string, string> ValidateAndFillParameters(Dictionary<string, string> providedParams)
    {
        var result = new Dictionary<string, string>(providedParams);
        var missingParams = new List<string>();

        foreach (var param in _parameters)
        {
            if (!result.ContainsKey(param.Name))
            {
                if (param.IsRequired && string.IsNullOrEmpty(param.DefaultValue))
                {
                    missingParams.Add(param.Name);
                }
                else if (!string.IsNullOrEmpty(param.DefaultValue))
                {
                    result[param.Name] = param.DefaultValue;
                }
            }
        }

        if (missingParams.Count > 0)
        {
            throw new MissingTemplateParametersException(missingParams);
        }

        return result;
    }

    /// <summary>
    /// EN: Mark template as approved.
    /// VI: Đánh dấu mẫu đã được phê duyệt.
    /// </summary>
    public void Approve()
    {
        Status = TemplateStatus.Approved;
        UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Mark template as rejected.
    /// VI: Đánh dấu mẫu bị từ chối.
    /// </summary>
    public void Reject()
    {
        Status = TemplateStatus.Rejected;
        UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Record that this template was sent.
    /// VI: Ghi nhận mẫu này đã được gửi.
    /// </summary>
    public void RecordSend()
    {
        SendCount++;
        UpdatedAt = DateTime.UtcNow;
    }

    /// <summary>
    /// EN: Update template details.
    /// VI: Cập nhật chi tiết mẫu.
    /// </summary>
    public void Update(string name, string content)
    {
        Name = name ?? throw new ArgumentNullException(nameof(name));
        Content = content ?? throw new ArgumentNullException(nameof(content));
        UpdatedAt = DateTime.UtcNow;
    }
}
