using FluentValidation;
using ChatService.API.Application.Commands.Conversations;
using ChatService.API.Application.Commands.Messages;

namespace ChatService.API.Application.Validations.Messaging;

/// <summary>
/// EN: Validator for CreateConversationCommand.
/// VI: Validator cho CreateConversationCommand.
/// </summary>
public class CreateConversationCommandValidator : AbstractValidator<CreateConversationCommand>
{
    public CreateConversationCommandValidator()
    {
        RuleFor(x => x.CreatorId)
            .NotEmpty().WithMessage("CreatorId is required");

        RuleFor(x => x.ParticipantIds)
            .NotEmpty().WithMessage("At least one participant is required")
            .Must(x => x.Distinct().Count() == x.Count())
            .WithMessage("Participant IDs must be unique");

        When(x => x.IsGroup, () =>
        {
            RuleFor(x => x.Name)
                .NotEmpty().WithMessage("Group name is required for group conversations")
                .MaximumLength(100).WithMessage("Group name must be at most 100 characters");

            RuleFor(x => x.ParticipantIds)
                .Must(x => x.Count() >= 1)
                .WithMessage("Group conversation must have at least 1 participant besides the creator");
        });

        When(x => !x.IsGroup, () =>
        {
            RuleFor(x => x.ParticipantIds)
                .Must(x => x.Count() == 1)
                .WithMessage("Direct conversation must have exactly 1 participant besides the creator");
        });

        RuleFor(x => x.AvatarUrl)
            .MaximumLength(500).WithMessage("Avatar URL must be at most 500 characters")
            .When(x => !string.IsNullOrEmpty(x.AvatarUrl));
    }
}

/// <summary>
/// EN: Validator for SendMessageCommand.
/// VI: Validator cho SendMessageCommand.
/// </summary>
public class SendMessageCommandValidator : AbstractValidator<SendMessageCommand>
{
    private static readonly HashSet<string> ValidMessageTypes = new()
    {
        "text", "image", "video", "audio", "file", "location", "contact", "sticker", "system"
    };

    public SendMessageCommandValidator()
    {
        RuleFor(x => x.ConversationId)
            .NotEmpty().WithMessage("ConversationId is required");

        RuleFor(x => x.SenderId)
            .NotEmpty().WithMessage("SenderId is required");

        RuleFor(x => x.EncryptedContent)
            .NotEmpty().WithMessage("EncryptedContent is required")
            .MaximumLength(100000).WithMessage("EncryptedContent must be at most 100000 characters");

        RuleFor(x => x.Nonce)
            .NotEmpty().WithMessage("Nonce is required")
            .MaximumLength(100).WithMessage("Nonce must be at most 100 characters");

        RuleFor(x => x.AuthTag)
            .MaximumLength(100).WithMessage("AuthTag must be at most 100 characters")
            .When(x => !string.IsNullOrEmpty(x.AuthTag));

        RuleFor(x => x.MessageType)
            .Must(type => ValidMessageTypes.Contains(type.ToLowerInvariant()))
            .WithMessage($"MessageType must be one of: {string.Join(", ", ValidMessageTypes)}");

        RuleFor(x => x.Metadata)
            .MaximumLength(10000).WithMessage("Metadata must be at most 10000 characters")
            .When(x => !string.IsNullOrEmpty(x.Metadata));
    }
}

/// <summary>
/// EN: Validator for MarkMessagesReadCommand.
/// VI: Validator cho MarkMessagesReadCommand.
/// </summary>
public class MarkMessagesReadCommandValidator : AbstractValidator<MarkMessagesReadCommand>
{
    public MarkMessagesReadCommandValidator()
    {
        RuleFor(x => x.ConversationId)
            .NotEmpty().WithMessage("ConversationId is required");

        RuleFor(x => x.UserId)
            .NotEmpty().WithMessage("UserId is required");

        // EN: At least one of LastReadMessageId or ReadUpTo should be provided, or both can be null (mark all)
        // VI: Ít nhất một trong LastReadMessageId hoặc ReadUpTo nên được cung cấp, hoặc cả hai có thể null (đánh dấu tất cả)
        RuleFor(x => x)
            .Must(x => true) // EN: Always valid - all scenarios are handled / VI: Luôn hợp lệ - tất cả scenarios được xử lý
            .WithMessage("Either LastReadMessageId, ReadUpTo, or neither (to mark all) should be provided");
    }
}
