using Tiku.Application.Auth;
using Tiku.Domain.Identity;
using Tiku.Domain.Tenancy;

namespace Tiku.Application.Security;

public enum AuthorizationCacheMode
{
    Disabled,
    Shadow,
    Active
}

public sealed class AuthorizationCacheOptions
{
    public const string SectionName = "Security:AuthorizationCache";
    public AuthorizationCacheMode Mode { get; set; } = AuthorizationCacheMode.Disabled;
    public int LocalSnapshotSeconds { get; set; } = 60;
    public int DistributedStateSeconds { get; set; } = 60;
    public int DistributedSnapshotSeconds { get; set; } = 300;
    public int JitterPercent { get; set; } = 20;
}

public sealed record CachedSessionSecurityState(
    Guid SessionId,
    Guid UserId,
    AuthRealm Realm,
    Guid? TenantId,
    string SecurityStamp,
    DateTimeOffset ExpiresAt,
    bool Revoked);

public sealed record CachedUserSecurityState(Guid UserId, UserStatus Status, string SecurityStamp);

public sealed record CachedTenantSecurityState(Guid TenantId, TenantStatus Status);

public sealed record CachedMembershipSecurityState(Guid TenantId, Guid UserId, MembershipStatus Status);

public sealed record CachedPlatformAccessState(Guid UserId, long AuthorizationVersion, bool Allowed);

public sealed record CachedAuthorizationVersion(AuthRealm Realm, Guid? TenantId, long Version);

public sealed record AccessSecurityCacheLookup(Guid SessionId, Guid UserId, AuthRealm Realm, Guid? TenantId);

public sealed record AccessSecurityCacheState(
    CachedSessionSecurityState? Session,
    CachedUserSecurityState? User,
    CachedTenantSecurityState? Tenant,
    CachedMembershipSecurityState? Membership,
    CachedPlatformAccessState? PlatformAccess,
    CachedAuthorizationVersion? AuthorizationVersion)
{
    public bool Complete => Session is not null && User is not null && AuthorizationVersion is not null &&
                            ((Session.Realm == AuthRealm.Platform && PlatformAccess is not null) ||
                             (Session.Realm == AuthRealm.Tenant && Tenant is not null && Membership is not null));
}

public sealed record CachedAuthorizationSnapshot(long Version, CurrentAccessSnapshot Snapshot);

public interface IAccessSecurityCache
{
    bool IsConfigured { get; }

    Task<AccessSecurityCacheState?> GetAsync(AccessSecurityCacheLookup lookup,
        CancellationToken cancellationToken = default);

    Task SetAsync(AccessSecurityCacheState state, CancellationToken cancellationToken = default);
    Task InvalidateSessionAsync(Guid sessionId, CancellationToken cancellationToken = default);
    Task InvalidateUserAsync(Guid userId, CancellationToken cancellationToken = default);
    Task InvalidateTenantAsync(Guid tenantId, CancellationToken cancellationToken = default);
    Task InvalidateMembershipAsync(Guid tenantId, Guid userId, CancellationToken cancellationToken = default);

    Task SetAuthorizationVersionAsync(AuthRealm realm, Guid? tenantId, long version,
        CancellationToken cancellationToken = default);
}

public interface IAuthorizationSnapshotCache
{
    Task<CachedAuthorizationSnapshot?> GetAsync(AuthRealm realm, Guid? tenantId, Guid userId,
        CancellationToken cancellationToken = default);

    Task SetAsync(AuthRealm realm, Guid? tenantId, Guid userId, CachedAuthorizationSnapshot snapshot,
        CancellationToken cancellationToken = default);
}

public interface IAuthorizationStateInvalidator
{
    Task InvalidateSessionAsync(Guid sessionId, CancellationToken cancellationToken = default);
    Task InvalidateUserAsync(Guid userId, CancellationToken cancellationToken = default);
    Task InvalidateTenantAsync(Guid tenantId, CancellationToken cancellationToken = default);
    Task InvalidateMembershipAsync(Guid tenantId, Guid userId, CancellationToken cancellationToken = default);
    Task<long> BumpScopeAsync(AuthRealm realm, Guid? tenantId, CancellationToken cancellationToken = default);
}

public interface IAuthorizationCacheInvalidationProcessor
{
    Task<int> ProcessPendingAsync(int batchSize = 100, CancellationToken cancellationToken = default);
}

public interface IRequestAccessValidator
{
    Task<AuthSessionValidationResult?> ValidateAsync(
        Guid sessionId,
        Guid userId,
        AuthRealm realm,
        Guid? tenantId,
        CancellationToken cancellationToken = default);
}

public sealed class AuthorizationSecurityUnavailableException(Exception innerException)
    : Exception("Authentication security dependencies are unavailable.", innerException);