using System.Text.Json;
using Tiku.Domain.Commerce;
using Tiku.Domain.Platform;
using Tiku.Domain.Tenancy;
using Tiku.Domain.Identity;

namespace Tiku.Application.PlatformAdmin;

public sealed record PlatformAdminActor(Guid UserId);

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

public sealed record PlatformOverview(
    int TenantCount,
    int ActiveTenantCount,
    int SuspendedTenantCount,
    int OrderCount,
    int PaidOrderCount,
    int RevenueCents,
    int QuestionBankCount,
    int QuestionCount,
    int LearningActiveUserCount);

public sealed record PlatformTenantList(IReadOnlyCollection<PlatformTenantItem> Items);

public sealed record PlatformTenantItem(
    Guid Id,
    string Slug,
    string Name,
    string? LegalName,
    TenantStatus Status,
    TenantMode Mode,
    BillingStatus BillingStatus,
    DateTimeOffset? SubscriptionExpiresAt,
    int DomainCount,
    DateTimeOffset CreatedAt,
    DateTimeOffset UpdatedAt);

public sealed record PlatformTenantDetail(
    PlatformTenantItem Tenant,
    IReadOnlyCollection<PlatformTenantDomainItem> Domains,
    IReadOnlyCollection<PlatformTenantSubscriptionItem> Subscriptions,
    TenantBillingProfileItem? BillingProfile);

public sealed record PlatformTenantDomainItem(
    Guid Id,
    Guid TenantId,
    string Host,
    TenantDomainType DomainType,
    TenantDomainStatus Status,
    bool IsPrimary,
    DateTimeOffset? VerifiedAt,
    DateTimeOffset? DnsVerifiedAt,
    DateTimeOffset? TlsReadyAt,
    DateTimeOffset? LastCheckedAt,
    string? LastFailureReason);

public sealed record PlatformTenantSubscriptionItem(
    Guid Id,
    Guid TenantId,
    string PlanCode,
    TenantSubscriptionStatus Status,
    DateTimeOffset? StartsAt,
    DateTimeOffset? ExpiresAt,
    string? BillingCycle,
    int AmountCents,
    JsonElement Metadata);

public sealed record TenantBillingProfileItem(
    Guid TenantId,
    string? BillingName,
    string? TaxId,
    string? ContactName,
    string? ContactPhoneMasked,
    string? ContactEmail,
    string? BillingAddress,
    string? InvoiceTitle,
    TenantInvoiceTitleType? InvoiceType,
    string? BankName,
    string? BankAccountMasked,
    JsonElement Metadata);

public sealed record CreatePlatformTenantCommand(
    string Slug,
    string Name,
    string? LegalName,
    TenantStatus Status,
    BillingStatus BillingStatus,
    JsonElement Metadata);

public sealed record UpdatePlatformTenantStatusCommand(
    Guid TenantId,
    TenantStatus Status,
    BillingStatus BillingStatus,
    string? Reason);

public sealed record UpsertPlatformTenantBillingProfileCommand(
    Guid TenantId,
    string? BillingName,
    string? TaxId,
    string? ContactName,
    string? ContactPhone,
    string? ContactEmail,
    string? BillingAddress,
    string? InvoiceTitle,
    TenantInvoiceTitleType? InvoiceType,
    string? BankName,
    string? BankAccountMasked,
    JsonElement Metadata);

public sealed record PlatformPlanList(IReadOnlyCollection<PlatformSaasPlan> Items);

public sealed record PlatformPlanModuleEntitlements(
    string PlanCode,
    IReadOnlyCollection<string> ModuleCodes);

public sealed record ReplacePlatformPlanModulesCommand(
    string PlanCode,
    IReadOnlyCollection<string> ModuleCodes);

public sealed record PlatformTenantModuleOverrideItem(
    Guid TenantId,
    string ModuleCode,
    TenantModuleOverrideMode Mode,
    DateTimeOffset? ExpiresAt,
    string? Reason);

public sealed record UpsertPlatformTenantModuleOverrideCommand(
    Guid TenantId,
    string ModuleCode,
    TenantModuleOverrideMode Mode,
    DateTimeOffset? ExpiresAt,
    string Reason);

public sealed record UpsertPlatformSubscriptionCommand(
    Guid TenantId,
    string PlanCode,
    TenantSubscriptionStatus Status,
    DateTimeOffset? StartsAt,
    DateTimeOffset? ExpiresAt,
    string? BillingCycle,
    int AmountCents,
    JsonElement Metadata);

public sealed record PlatformDomainList(IReadOnlyCollection<PlatformTenantDomainItem> Items);

public sealed record PlatformDomainRecheckResult(Guid DomainId, TenantDomainStatus Status, DateTimeOffset LastCheckedAt);

public sealed record PlatformStaffList(IReadOnlyCollection<PlatformStaffItem> Items);

public sealed record PlatformStaffItem(
    Guid UserId,
    string? Name,
    string? PhoneMasked,
    string? Email,
    UserStatus Status,
    IReadOnlyCollection<string> RoleCodes,
    DateTimeOffset CreatedAt,
    DateTimeOffset UpdatedAt);

public sealed record UpsertPlatformStaffCommand(
    Guid? UserId,
    string? Email,
    string? Phone,
    string? Name,
    UserStatus Status,
    IReadOnlyCollection<Guid> RoleIds);

public sealed record UpdatePlatformStaffStatusCommand(Guid UserId, UserStatus Status, string? Reason);

public sealed record PlatformAuditLogList(IReadOnlyCollection<PlatformAuditLogItem> Items);

public sealed record PlatformAuditLogItem(
    Guid Id,
    Guid? TenantId,
    Guid? ActorUserId,
    string Action,
    string? TargetType,
    string? TargetId,
    JsonElement Details,
    string? IpAddress,
    string? UserAgent,
    DateTimeOffset CreatedAt);

public sealed record PlatformAuditAlertList(IReadOnlyCollection<PlatformAuditAlert> Items);

public sealed record UpdatePlatformAuditAlertStatusCommand(
    Guid AlertId,
    PlatformAuditAlertStatus Status,
    string? ResolutionNote);

public sealed record PlatformDunningChannelList(IReadOnlyCollection<PlatformDunningChannelItem> Items);

public sealed record PlatformDunningChannelItem(
    Guid Id,
    string ChannelCode,
    string Name,
    string? Description,
    bool Enabled,
    PlatformDunningProvider Provider,
    string WebhookUrlMasked,
    string? SecretRef,
    IReadOnlyCollection<string> ReminderTypes,
    IReadOnlyCollection<string> ReminderChannels,
    int MinReminderLevel,
    IReadOnlyCollection<Guid> TenantIds,
    int TimeoutSeconds,
    JsonElement Metadata,
    DateTimeOffset CreatedAt,
    DateTimeOffset UpdatedAt);

public sealed record UpsertPlatformDunningChannelCommand(
    Guid? ChannelId,
    string ChannelCode,
    string Name,
    string? Description,
    bool Enabled,
    PlatformDunningProvider Provider,
    string WebhookUrl,
    string? SecretRef,
    IReadOnlyCollection<string> ReminderTypes,
    IReadOnlyCollection<string> ReminderChannels,
    int MinReminderLevel,
    IReadOnlyCollection<Guid> TenantIds,
    int TimeoutSeconds,
    JsonElement Metadata);

public sealed record DisablePlatformDunningChannelCommand(Guid ChannelId, string? Reason);

public sealed record PlatformDunningEventList(IReadOnlyCollection<PlatformDunningEventItem> Items);

public sealed record PlatformDunningEventItem(
    Guid Id,
    Guid TenantId,
    Guid ChannelId,
    Guid ReminderId,
    Guid InvoiceId,
    PlatformDunningProvider Provider,
    PlatformDunningNotificationStatus Status,
    int Attempts,
    DateTimeOffset ScheduledAt,
    DateTimeOffset? NextAttemptAt,
    DateTimeOffset? LastAttemptAt,
    DateTimeOffset? SentAt,
    string? LastError,
    int? LastHttpCode,
    string? LastResponseSummary,
    JsonElement RequestPayload,
    JsonElement Metadata,
    DateTimeOffset CreatedAt,
    DateTimeOffset UpdatedAt);

public sealed record RetryPlatformDunningEventCommand(Guid EventId, string? Reason);

public interface IPlatformAdminService
{
    Task<PlatformOverview> GetOverviewAsync(PlatformAdminActor actor, CancellationToken cancellationToken = default);
    Task<PlatformTenantList> GetTenantsAsync(PlatformAdminActor actor, PlatformAdminQuery query, CancellationToken cancellationToken = default);
    Task<PlatformTenantDetail> GetTenantDetailAsync(PlatformAdminActor actor, Guid tenantId, CancellationToken cancellationToken = default);
    Task<PlatformTenantItem> CreateTenantAsync(PlatformAdminActor actor, CreatePlatformTenantCommand command, CancellationToken cancellationToken = default);
    Task<PlatformTenantItem> UpdateTenantStatusAsync(PlatformAdminActor actor, UpdatePlatformTenantStatusCommand command, CancellationToken cancellationToken = default);
    Task<TenantBillingProfileItem> UpsertTenantBillingProfileAsync(PlatformAdminActor actor, UpsertPlatformTenantBillingProfileCommand command, CancellationToken cancellationToken = default);
    Task<PlatformPlanList> GetPlansAsync(PlatformAdminActor actor, PlatformAdminQuery query, CancellationToken cancellationToken = default);
    Task<PlatformPlanModuleEntitlements> ReplacePlanModulesAsync(PlatformAdminActor actor, ReplacePlatformPlanModulesCommand command, CancellationToken cancellationToken = default);
    Task<PlatformTenantSubscriptionItem> UpsertSubscriptionAsync(PlatformAdminActor actor, UpsertPlatformSubscriptionCommand command, CancellationToken cancellationToken = default);
    Task<PlatformTenantModuleOverrideItem> UpsertTenantModuleOverrideAsync(PlatformAdminActor actor, UpsertPlatformTenantModuleOverrideCommand command, CancellationToken cancellationToken = default);
    Task<PlatformDomainList> GetDomainsAsync(PlatformAdminActor actor, PlatformAdminQuery query, CancellationToken cancellationToken = default);
    Task<PlatformDomainRecheckResult> RecheckDomainAsync(PlatformAdminActor actor, Guid domainId, CancellationToken cancellationToken = default);
    Task<PlatformStaffList> GetStaffAsync(PlatformAdminActor actor, PlatformAdminQuery query, CancellationToken cancellationToken = default);
    Task<PlatformStaffItem> UpsertStaffAsync(PlatformAdminActor actor, UpsertPlatformStaffCommand command, CancellationToken cancellationToken = default);
    Task<PlatformStaffItem> UpdateStaffStatusAsync(PlatformAdminActor actor, UpdatePlatformStaffStatusCommand command, CancellationToken cancellationToken = default);
    Task<PlatformAuditLogList> GetAuditLogsAsync(PlatformAdminActor actor, PlatformAdminQuery query, CancellationToken cancellationToken = default);
    Task<PlatformAuditAlertList> GetAuditAlertsAsync(PlatformAdminActor actor, PlatformAdminQuery query, CancellationToken cancellationToken = default);
    Task<PlatformAuditAlert> UpdateAuditAlertStatusAsync(PlatformAdminActor actor, UpdatePlatformAuditAlertStatusCommand command, CancellationToken cancellationToken = default);
    Task<PlatformDunningChannelList> GetDunningChannelsAsync(PlatformAdminActor actor, PlatformAdminQuery query, CancellationToken cancellationToken = default);
    Task<PlatformDunningChannelItem> UpsertDunningChannelAsync(PlatformAdminActor actor, UpsertPlatformDunningChannelCommand command, CancellationToken cancellationToken = default);
    Task<PlatformDunningChannelItem> DisableDunningChannelAsync(PlatformAdminActor actor, DisablePlatformDunningChannelCommand command, CancellationToken cancellationToken = default);
    Task<PlatformDunningEventList> GetDunningEventsAsync(PlatformAdminActor actor, PlatformAdminQuery query, CancellationToken cancellationToken = default);
    Task<PlatformDunningEventItem> GetDunningEventDetailAsync(PlatformAdminActor actor, Guid eventId, CancellationToken cancellationToken = default);
    Task<PlatformDunningEventItem> RetryDunningEventAsync(PlatformAdminActor actor, RetryPlatformDunningEventCommand command, CancellationToken cancellationToken = default);
}

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