using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace GmRelay.Shared.Features.Sessions.CreateSession.Wizard;

/// <summary>
/// Visual style for a wizard button. The platform adapter maps this to its
/// own native styling (Telegram currently ignores it; Discord uses it for
/// primary/danger/success button colors).
/// </summary>
public enum WizardActionStyle
{
    Primary,
    Secondary,
    Success,
    Danger,
}

/// <summary>
/// A single button on a wizard keyboard. <see cref="Payload"/> is the
/// platform-neutral callback token — usually produced by
/// <see cref="WizardCallbackData"/> but adapters are free to interpret
/// any string.
/// </summary>
public sealed record WizardAction(
    string Label,
    string Payload,
    WizardActionStyle Style = WizardActionStyle.Secondary);

/// <summary>
/// One row of buttons on a wizard keyboard. The platform adapter is
/// responsible for laying out rows; the wizard core returns a flat list
/// of actions and trusts the adapter to split them into rows.
/// </summary>
public sealed record WizardKeyboard(IReadOnlyList<WizardAction> Actions);

/// <summary>
/// A user-owned group/club selectable from the visibility step. Moved
/// from <c>GmRelay.Bot</c> so the wizard can ask for the list without
/// taking a dependency on Telegram.
/// </summary>
public sealed record WizardClubOption(Guid ClubId, string Name);

/// <summary>
/// Platform-neutral user interaction with the wizard. Adapters convert
/// their native event (Telegram <c>Update</c>, Discord interaction, …)
/// into one of these before handing it to <see cref="GameCreationWizard"/>.
/// </summary>
public sealed record WizardInteraction(
    string OwnerId,
    string? Text,
    string? CallbackPayload,
    string? PhotoFileId,
    string? PhotoUrl,
    string InteractionId);

/// <summary>
/// Storage contract for wizard drafts. Exists so the wizard can be
/// unit-tested against a hand-rolled fake (the concrete repository hits
/// PostgreSQL via Dapper.AOT and is therefore unsuitable for fast
/// in-process tests).
/// </summary>
public interface IWizardDraftRepository
{
    Task<WizardDraft?> GetActiveAsync(string platform, string ownerId, CancellationToken ct);

    Task UpsertAsync(WizardDraft draft, CancellationToken ct);

    Task DeleteAsync(Guid id, CancellationToken ct);

    Task<int> DeleteExpiredAsync(CancellationToken ct);
}

/// <summary>
/// Contract the wizard core uses to talk to the chat platform. Each
/// platform supplies its own implementation (Telegram today, Discord in
/// a follow-up task).
/// </summary>
public interface IWizardMessenger
{
    /// <summary>
    /// Edit the message that currently represents the wizard draft.
    /// Returns the new message id as a string — Telegram exposes
    /// <c>int32</c>, Discord uses 64-bit snowflakes, both fit in
    /// <see cref="string"/> for cross-platform uniformity.
    /// </summary>
    Task<string> EditDraftMessageAsync(
        WizardDraft draft,
        string text,
        IReadOnlyList<WizardAction> keyboard,
        CancellationToken ct);

    /// <summary>
    /// Post a fresh wizard draft message and return its id.
    /// </summary>
    Task<string> SendDraftMessageAsync(
        WizardDraft draft,
        string text,
        IReadOnlyList<WizardAction> keyboard,
        CancellationToken ct);

    /// <summary>
    /// Acknowledge a callback / interaction. <paramref name="text"/>
    /// is an optional toast the user sees briefly.
    /// </summary>
    Task AnswerInteractionAsync(string interactionId, string? text, CancellationToken ct);

    /// <summary>
    /// List the clubs/groups the owner manages. The platform
    /// implementation decides how to query the database — the wizard
    /// core only needs a list of (id, name) pairs.
    /// </summary>
    Task<IReadOnlyList<WizardClubOption>> GetOwnerClubsAsync(string ownerId, CancellationToken ct);
}
