using System.Text.Json;

namespace Tiku.Application.Commerce;

public static class PaymentProviders
{
    public const string WechatPay = "wechat_pay";
    public const string Alipay = "alipay";
    public const string Manual = "manual";
}

public sealed record PaymentProviderAccount(
    Guid TenantId,
    string Provider,
    string Mode,
    JsonElement ConfigPublic,
    JsonElement SecretPayload);

public sealed record CreatePaymentProviderRequest(
    Guid TenantId,
    string OrderNo,
    string Subject,
    int AmountCents,
    string Method,
    string? OpenId,
    string? ReturnUrl,
    string? QuitUrl,
    string NotifyUrl,
    JsonElement Metadata);

public sealed record CreatePaymentProviderResult(
    string Provider,
    string Method,
    string Status,
    string? ProviderTradeNo,
    JsonElement ClientPayload,
    JsonElement RawPayload);

public sealed record PaymentNotificationRequest(
    Guid TenantId,
    string Provider,
    IReadOnlyDictionary<string, string> Headers,
    string RawBody,
    JsonElement Body);

public sealed record PaymentNotificationResult(
    string Provider,
    string EventType,
    string EventId,
    string OrderNo,
    string? ProviderTradeNo,
    int AmountCents,
    bool Paid,
    bool SignatureValid,
    DateTimeOffset? PaidAt,
    JsonElement RawPayload);

public interface IPaymentProvider
{
    string Provider { get; }

    Task<CreatePaymentProviderResult> CreatePaymentAsync(
        PaymentProviderAccount account,
        CreatePaymentProviderRequest request,
        CancellationToken cancellationToken = default);

    Task<PaymentNotificationResult> ParsePaymentNotificationAsync(
        PaymentProviderAccount account,
        PaymentNotificationRequest request,
        CancellationToken cancellationToken = default);
}

public interface IPaymentProviderGateway
{
    Task<CreatePaymentProviderResult> CreatePaymentAsync(
        string provider,
        CreatePaymentProviderRequest request,
        CancellationToken cancellationToken = default);

    Task<PaymentNotificationResult> ParsePaymentNotificationAsync(
        string provider,
        PaymentNotificationRequest request,
        CancellationToken cancellationToken = default);
}

public interface IPaymentProviderConfigService
{
    Task<PaymentProviderAccount> GetActiveAccountAsync(
        Guid tenantId,
        string provider,
        CancellationToken cancellationToken = default);
}

public interface ITenantSecretService
{
    Task<JsonElement> GetActiveSecretPayloadAsync(
        Guid tenantId,
        string secretRef,
        CancellationToken cancellationToken = default);
}

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