using Dapper;
using GmRelay.Bot.Features.Notifications;
using GmRelay.Shared.Domain;
using Npgsql;
using Telegram.Bot;

namespace GmRelay.Bot.Features.Reminders.SendJoinLink;

// ── DTOs ─────────────────────────────────────────────────────────────

internal sealed record JoinLinkSession(
    Guid Id,
    string Title,
    string JoinLink,
    DateTime ScheduledAt,
    long TelegramChatId,
    string NotificationMode);

internal sealed record ConfirmedPlayer(
    long TelegramId,
    string DisplayName,
    string? TelegramUsername);

// ── Handler ──────────────────────────────────────────────────────────

/// <summary>
/// Sends the join link to the group chat at T-5min, tagging all confirmed players.
/// Called by SessionSchedulerService.
/// </summary>
public sealed class SendJoinLinkHandler(
    NpgsqlDataSource dataSource,
    ITelegramBotClient bot,
    DirectSessionNotificationSender directSender,
    ILogger<SendJoinLinkHandler> logger) : ISendJoinLinkHandler
{
    public async Task HandleAsync(Guid sessionId, CancellationToken ct)
    {
        await using var connection = await dataSource.OpenConnectionAsync(ct);

        // 1. Load session
        var session = await connection.QuerySingleOrDefaultAsync<JoinLinkSession>(
            """
            SELECT s.id, s.title, s.join_link AS JoinLink, s.scheduled_at AS ScheduledAt,
                   g.telegram_chat_id AS TelegramChatId,
                   s.notification_mode AS NotificationMode
            FROM sessions s
            JOIN game_groups g ON g.id = s.group_id
            WHERE s.id = @SessionId
              AND s.status = @Confirmed
              AND s.link_message_id IS NULL
            """,
            new { SessionId = sessionId, Confirmed = SessionStatus.Confirmed });

        if (session is null)
        {
            logger.LogWarning("Session {SessionId} not eligible for join link", sessionId);
            return;
        }

        // 2. Load confirmed players
        var players = (await connection.QueryAsync<ConfirmedPlayer>(
            """
            SELECT p.telegram_id    AS TelegramId,
                   p.display_name    AS DisplayName,
                   p.telegram_username AS TelegramUsername
            FROM session_participants sp
            JOIN players p ON p.id = sp.player_id
            WHERE sp.session_id = @SessionId
              AND sp.rsvp_status = @Confirmed
              AND sp.registration_status = @Active
            """,
            new
            {
                SessionId = sessionId,
                Confirmed = RsvpStatus.Confirmed,
                Active = ParticipantRegistrationStatus.Active
            })).ToList();

        // 3. Build message with player mentions
        var mentions = string.Join(", ", players.Select(p =>
            p.TelegramUsername is not null ? $"@{p.TelegramUsername}" : p.DisplayName));

        var text = $"""
            🎮 Игра «{session.Title}» начинается через 5 минут!

            🔗 Ссылка на подключение:
            {session.JoinLink}

            Участники: {mentions}

            Хорошей игры! 🎲
            """;

        // 4. Send
        var message = await bot.SendMessage(
            chatId: session.TelegramChatId,
            text: text,
            cancellationToken: ct);

        // 5. Mark as sent (idempotent — link_message_id IS NULL guard in query)
        await connection.ExecuteAsync(
            """
            UPDATE sessions
            SET    link_message_id = @MessageId, updated_at = now()
            WHERE  id = @SessionId AND link_message_id IS NULL
            """,
            new { SessionId = sessionId, MessageId = message.MessageId });

        var mode = SessionNotificationModeExtensions.FromDatabaseValue(session.NotificationMode);
        if (mode.ShouldSendDirectMessages())
        {
            var directText = $"""
                🎮 <b>Игра начинается через 5 минут</b>

                📌 <b>{System.Net.WebUtility.HtmlEncode(session.Title)}</b>
                🔗 {System.Net.WebUtility.HtmlEncode(session.JoinLink)}
                """;

            await directSender.SendAsync(
                players.Select(p => new DirectNotificationRecipient(p.TelegramId, p.DisplayName)),
                directText,
                "join-link",
                sessionId,
                ct);
        }

        logger.LogInformation(
            "Join link sent for session {SessionId} ({Title}), message_id={MessageId}",
            sessionId, session.Title, message.MessageId);
    }
}
