using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Ablera.Serdica.Authentication.Models;
using Ablera.Serdica.Authority.Models;

namespace Ablera.Serdica.Authority.Services;

public sealed class RedisTicketStore(IDistributedCache cache, IOptions<OidcServerSettings> options) : ITicketStore
{
    private static readonly TicketSerializer serializer = TicketSerializer.Default;
    private const string Prefix = "auth_ticket_";
    private readonly TimeSpan lifetime = TimeSpan.FromMinutes(options.Value.CookieExpirationInMinutes);

    public async Task<string> StoreAsync(AuthenticationTicket ticket)
    {
        var key = CreateKey();
        await RenewAsync(key, ticket);
        return key; 
    }

    public Task RenewAsync(string key, AuthenticationTicket ticket)
    {
        var bytes = serializer.Serialize(ticket);
        var opts = new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = lifetime,
            SlidingExpiration = lifetime
        };
        return cache.SetAsync(Prefix + key, bytes, opts);
    }

    public async Task<AuthenticationTicket?> RetrieveAsync(string key)
    {
        var bytes = await cache.GetAsync(Prefix + key);
        return bytes is null ? null : serializer.Deserialize(bytes);
    }

    public Task RemoveAsync(string key)
        => cache.RemoveAsync(Prefix + key);

    // --------------- helpers ----------------------
    private static string CreateKey()
    {
        // 32 random bytes –> SHA-256 –> Base64-url
        Span<byte> rnd = stackalloc byte[32];
        RandomNumberGenerator.Fill(rnd);
        Span<byte> hash = stackalloc byte[32];
        SHA256.HashData(rnd, hash);

        return WebEncoders.Base64UrlEncode(hash);
    }
}
