using FluentValidation;
using TakeoutSaaS.Application.App.Orders.Commands;
using TakeoutSaaS.Domain.Orders.Enums;
using TakeoutSaaS.Domain.Payments.Enums;

namespace TakeoutSaaS.Application.App.Orders.Validators;

/// <summary>
/// 创建订单命令验证器。
/// </summary>
public sealed class CreateOrderCommandValidator : AbstractValidator<CreateOrderCommand>
{
    /// <summary>
    /// 初始化验证规则。
    /// </summary>
    public CreateOrderCommandValidator()
    {
        RuleFor(x => x.OrderNo).NotEmpty().MaximumLength(32);
        RuleFor(x => x.StoreId).GreaterThan(0);
        RuleFor(x => x.CustomerPhone).MaximumLength(32);
        RuleFor(x => x.CustomerName).MaximumLength(64);
        RuleFor(x => x.TableNo).MaximumLength(32);
        RuleFor(x => x.QueueNumber).MaximumLength(32);
        RuleFor(x => x.CancelReason).MaximumLength(256);
        RuleFor(x => x.Remark).MaximumLength(512);
        RuleFor(x => x.ItemsAmount).GreaterThanOrEqualTo(0);
        RuleFor(x => x.DiscountAmount).GreaterThanOrEqualTo(0);
        RuleFor(x => x.PayableAmount).GreaterThanOrEqualTo(0);
        RuleFor(x => x.PaidAmount).GreaterThanOrEqualTo(0);
        RuleFor(x => x.PayableAmount)
            .Must((cmd, payable) => payable == cmd.ItemsAmount - cmd.DiscountAmount)
            .WithMessage("应付金额必须等于商品金额减去优惠金额");
        RuleFor(x => x.PaidAmount)
            .LessThanOrEqualTo(x => x.PayableAmount)
            .WithMessage("实付金额不得超过应付金额");

        RuleFor(x => x.PaymentStatus)
            .Must(status => status is PaymentStatus.Unpaid or PaymentStatus.Paying or PaymentStatus.Paid or PaymentStatus.Failed or PaymentStatus.Refunded)
            .WithMessage("支付状态不合法");
        When(x => x.PaymentStatus == PaymentStatus.Paid, () =>
        {
            RuleFor(x => x.PaidAt).NotNull().WithMessage("支付成功必须包含支付时间");
            RuleFor(x => x.PaidAmount).GreaterThan(0).WithMessage("支付成功时实付金额必须大于 0");
        });
        When(x => x.PaymentStatus != PaymentStatus.Paid, () =>
        {
            RuleFor(x => x.PaidAt).Must(paidAt => paidAt == null).WithMessage("非支付成功状态不应包含支付时间");
        });
        When(x => x.PaymentStatus == PaymentStatus.Refunded, () =>
        {
            RuleFor(x => x.PaidAmount).GreaterThanOrEqualTo(0).WithMessage("退款状态下实付金额需合法");
        });
        When(x => x.Status == OrderStatus.Cancelled, () =>
        {
            RuleFor(x => x.CancelReason).NotEmpty().WithMessage("取消订单必须提供取消原因");
        });
        When(x => x.Status != OrderStatus.Cancelled, () =>
        {
            RuleFor(x => x.CancelReason).Must(reason => string.IsNullOrWhiteSpace(reason)).WithMessage("非取消状态不应包含取消原因");
        });

        RuleFor(x => x.Items)
            .NotEmpty()
            .WithMessage("订单明细不能为空");

        RuleForEach(x => x.Items).ChildRules(item =>
        {
            item.RuleFor(i => i.ProductId).GreaterThan(0);
            item.RuleFor(i => i.ProductName).NotEmpty().MaximumLength(128);
            item.RuleFor(i => i.SkuName).MaximumLength(128);
            item.RuleFor(i => i.Unit).MaximumLength(16);
            item.RuleFor(i => i.Quantity).GreaterThan(0);
            item.RuleFor(i => i.UnitPrice).GreaterThanOrEqualTo(0);
            item.RuleFor(i => i.DiscountAmount).GreaterThanOrEqualTo(0);
            item.RuleFor(i => i.SubTotal).GreaterThanOrEqualTo(0);
            item.RuleFor(i => i.AttributesJson).MaximumLength(4000);
        });
    }
}
