using System.Text.Json;

namespace Tiku.Application.Commerce;

public sealed record CommerceActor(Guid TenantId, Guid UserId);

public sealed record CreateCommerceOrderCommand(
    Guid PlanId,
    int Quantity,
    string? PayMethod,
    string? PayProvider,
    Guid? RegionId,
    string? CouponCode,
    Guid? CouponRedemptionId);

public sealed record CommerceOrderQuery(int? Limit = null, string? Status = null);

public sealed record CreateCommercePaymentCommand(
    string OrderNo,
    string Provider,
    string Method,
    string? OpenId,
    string? ReturnUrl,
    string? QuitUrl);

public sealed record CommerceOrderItem(
    Guid Id,
    string OrderNo,
    string Status,
    Guid? PlanId,
    Guid? RegionId,
    string? ProductType,
    string? ProductName,
    int AmountCents,
    string Price,
    string? PayMethod,
    string? PayProvider,
    string? TradeNo,
    int? Days,
    DateTimeOffset? PaidAt,
    DateTimeOffset CreatedAt,
    JsonElement RawPayload);

public sealed record CommerceOrderList(IReadOnlyCollection<CommerceOrderItem> Items);

public sealed record CommercePaymentItem(
    Guid Id,
    Guid OrderId,
    string OrderNo,
    string Provider,
    string? Method,
    string Status,
    int AmountCents,
    string Price,
    string? ProviderTradeNo,
    DateTimeOffset? PaidAt,
    JsonElement ClientPayload,
    JsonElement RawPayload);

public sealed record CurrentEntitlementItem(
    bool IsActive,
    string EntitlementType,
    DateTimeOffset? StartsAt,
    DateTimeOffset? ExpiresAt,
    string Status,
    int? DaysLeft);

public sealed record CommerceCouponQuery(int? Limit = null, string? Status = null);

public sealed record ClaimCommerceCouponCommand(string CouponCode);

public sealed record CheckCommerceCouponCommand(
    string? CouponCode,
    Guid? CouponRedemptionId,
    Guid PlanId,
    int Quantity,
    Guid? RegionId);

public sealed record CommerceCouponItem(
    Guid Id,
    Guid? CouponId,
    string CouponCode,
    string Status,
    Guid? PlanId,
    Guid? RegionId,
    string? DiscountType,
    decimal? DiscountValue,
    int? DiscountPreviewCents,
    string? DiscountPreview,
    DateTimeOffset? ValidFrom,
    DateTimeOffset? ValidTo,
    DateTimeOffset? ClaimedAt,
    DateTimeOffset? UsedAt);

public sealed record CommerceCouponList(IReadOnlyCollection<CommerceCouponItem> Items);

public sealed record CommerceCouponCheckResult(
    bool Valid,
    string? ReasonCode,
    Guid? CouponId,
    Guid? CouponRedemptionId,
    string? CouponCode,
    int OriginalAmountCents,
    int DiscountCents,
    int PayableAmountCents,
    string PayablePrice);

public sealed record PaymentNotificationProcessResult(
    string Provider,
    string EventId,
    string OrderNo,
    string Status,
    bool Idempotent);

public interface ICommerceService
{
    Task<CommerceOrderItem> CreateOrderAsync(
        CommerceActor actor,
        CreateCommerceOrderCommand command,
        CancellationToken cancellationToken = default);

    Task<CommerceOrderList> GetOrdersAsync(
        CommerceActor actor,
        CommerceOrderQuery query,
        CancellationToken cancellationToken = default);

    Task<CommerceOrderItem> GetOrderAsync(
        CommerceActor actor,
        string orderNo,
        CancellationToken cancellationToken = default);

    Task<CommercePaymentItem> CreatePaymentAsync(
        CommerceActor actor,
        CreateCommercePaymentCommand command,
        CancellationToken cancellationToken = default);

    Task<CurrentEntitlementItem> GetCurrentEntitlementAsync(
        CommerceActor actor,
        CancellationToken cancellationToken = default);

    Task<CommerceCouponItem> ClaimCouponAsync(
        CommerceActor actor,
        ClaimCommerceCouponCommand command,
        CancellationToken cancellationToken = default);

    Task<CommerceCouponList> GetCouponsAsync(
        CommerceActor actor,
        CommerceCouponQuery query,
        CancellationToken cancellationToken = default);

    Task<CommerceCouponCheckResult> CheckCouponAsync(
        CommerceActor actor,
        CheckCommerceCouponCommand command,
        CancellationToken cancellationToken = default);

    Task<PaymentNotificationProcessResult> ProcessPaymentNotificationAsync(
        Guid tenantId,
        string provider,
        IReadOnlyDictionary<string, string> headers,
        string rawBody,
        JsonElement body,
        CancellationToken cancellationToken = default);
}

public sealed class CommerceException(string message, string code) : Exception(message)
{
    public string Code { get; } = code;
}