using System;
using System.Collections.Concurrent;

namespace GmRelay.DiscordBot.Features.Sessions.Wizard;

/// <summary>
/// Snapshot of where the wizard's draft message lives. The messenger
/// needs this to re-send / re-edit the message after a 15-minute
/// interaction token has expired.
/// </summary>
/// <param name="GuildId">Discord guild (server) id as a decimal string.</param>
/// <param name="ChannelId">Channel id where the draft message was posted.</param>
/// <param name="MessageId">Id of the currently active draft message.</param>
/// <param name="ThreadId">Optional thread id; <c>null</c> for top-level channel posts.</param>
public sealed record DiscordWizardContext(
    string GuildId,
    string ChannelId,
    string MessageId,
    string? ThreadId);

/// <summary>
/// In-memory store of draft → context lookups. Lives for the lifetime of
/// the process; the wizard's 24-hour expiry is enforced by
/// <c>WizardDraftCleanupService</c>, so this cache is allowed to hold
/// entries until the draft is finalized or explicitly removed.
/// </summary>
public interface IWizardContextStore
{
    void Set(Guid draftId, DiscordWizardContext context);

    bool TryGet(Guid draftId, out DiscordWizardContext context);

    void Remove(Guid draftId);
}

/// <summary>
/// Thread-safe in-memory implementation. Concurrent dictionary keyed by
/// <see cref="Guid"/> is sufficient for a single-process Discord bot.
/// </summary>
public sealed class DiscordWizardContextStore : IWizardContextStore
{
    private readonly ConcurrentDictionary<Guid, DiscordWizardContext> store = new();

    public void Set(Guid draftId, DiscordWizardContext context) =>
        store[draftId] = context;

    public bool TryGet(Guid draftId, out DiscordWizardContext context) =>
        store.TryGetValue(draftId, out context!);

    public void Remove(Guid draftId) => store.TryRemove(draftId, out _);
}
