using System.Text.Json;
using Tiku.Application.Backoffice;
using Tiku.Application.PlatformBilling;
using Tiku.Domain.Platform;

namespace Tiku.Application.PlatformAdmin;

public static class PlatformApprovalPolicyCodes
{
    public const string TenantArchive = "tenant.archive";
    public const string SuperAdminGrant = "security.super-admin-grant";
    public const string PaymentChannelChange = "payment.channel-change";
    public const string FinancialAdjustment = "finance.adjustment";
}

public sealed record PlatformApprovalActor(Guid UserId, IReadOnlySet<string> Permissions);

public sealed record PlatformCommandSubmission(
    string ExecutionStatus,
    JsonElement? Result,
    PlatformApprovalRequestItem? ApprovalRequest);

public sealed record PlatformApprovalRequestItem(
    Guid Id,
    string RequestNo,
    string PolicyCode,
    int PolicyVersion,
    PlatformApprovalRequestStatus Status,
    Guid RequestedBy,
    Guid? DecidedBy,
    string RequiredPermission,
    string CommandType,
    string TargetType,
    string TargetId,
    int? AmountCents,
    JsonElement RequestSnapshot,
    string? RequestReason,
    string? DecisionReason,
    string? Error,
    DateTimeOffset ExpiresAt,
    DateTimeOffset CreatedAt,
    DateTimeOffset UpdatedAt);

public sealed record PlatformApprovalPolicyItem(
    Guid Id,
    string Code,
    string Name,
    string RequiredPermission,
    bool Enabled,
    bool AlwaysRequireApproval,
    int? AmountThresholdCents,
    int Version,
    int ExpiresAfterHours,
    JsonElement Conditions);

public sealed record UpdatePlatformApprovalPolicyCommand(
    string Code,
    bool Enabled,
    bool AlwaysRequireApproval,
    int? AmountThresholdCents,
    int ExpiresAfterHours,
    JsonElement Conditions);

public interface IPlatformApprovalService
{
    Task<IReadOnlyCollection<PlatformApprovalRequestItem>> ListAsync(PlatformApprovalActor actor,
        PlatformApprovalRequestStatus? status, int limit, CancellationToken cancellationToken = default);

    Task<PlatformApprovalRequestItem> GetAsync(PlatformApprovalActor actor, Guid requestId,
        CancellationToken cancellationToken = default);

    Task<IReadOnlyCollection<PlatformApprovalPolicyItem>> ListPoliciesAsync(PlatformApprovalActor actor,
        CancellationToken cancellationToken = default);

    Task<PlatformApprovalPolicyItem> UpdatePolicyAsync(PlatformApprovalActor actor,
        UpdatePlatformApprovalPolicyCommand command, CancellationToken cancellationToken = default);

    Task<PlatformApprovalRequestItem> ApproveAsync(PlatformApprovalActor actor, Guid requestId, string reason,
        CancellationToken cancellationToken = default);

    Task<PlatformApprovalRequestItem> RejectAsync(PlatformApprovalActor actor, Guid requestId, string reason,
        CancellationToken cancellationToken = default);

    Task<PlatformApprovalRequestItem> CancelAsync(PlatformApprovalActor actor, Guid requestId, string reason,
        CancellationToken cancellationToken = default);

    Task<int> ProcessApprovedAsync(int batchSize = 20, CancellationToken cancellationToken = default);

    Task<PlatformCommandSubmission> SubmitRefundAsync(SaasCatalogActor actor, RequestPlatformRefundCommand command,
        CancellationToken cancellationToken = default);

    Task<PlatformCommandSubmission> ConfirmManualPaymentAsync(SaasCatalogActor actor,
        ConfirmManualPaymentCommand command, string idempotencyKey, CancellationToken cancellationToken = default);

    Task<PlatformCommandSubmission> UpdateTenantStatusAsync(PlatformAdminActor actor,
        UpdatePlatformTenantStatusCommand command, string idempotencyKey,
        CancellationToken cancellationToken = default);

    Task<PlatformCommandSubmission> UpsertPaymentChannelAsync(PlatformCapabilityActor actor,
        UpsertPlatformPaymentChannelCommand command, string idempotencyKey,
        CancellationToken cancellationToken = default);

    Task<PlatformCommandSubmission> ReplaceRoleBindingsAsync(BackofficeActor actor, ReplaceRoleBindingsCommand command,
        string idempotencyKey, CancellationToken cancellationToken = default);
}

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

public static class PlatformApprovalRules
{
    public static bool RequiresApproval(bool enabled, bool alwaysRequireApproval, int? amountThresholdCents,
        int? amountCents)
    {
        return enabled && (alwaysRequireApproval ||
                           (amountThresholdCents.HasValue && amountCents >= amountThresholdCents));
    }

    public static string? DecisionDenialCode(
        PlatformApprovalRequestStatus status,
        Guid requestedBy,
        Guid decisionActor,
        DateTimeOffset expiresAt,
        string requiredPermission,
        IReadOnlySet<string> permissions,
        DateTimeOffset now)
    {
        if (status != PlatformApprovalRequestStatus.Pending) return "approval_request_not_pending";
        if (expiresAt <= now) return "approval_request_expired";
        if (requestedBy == decisionActor) return "approval_maker_checker_required";
        return permissions.Contains(requiredPermission) ? null : "approval_business_permission_required";
    }
}