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

namespace GmRelay.Bot.Features.Reminders.SendOneHourReminder;

internal sealed record OneHourReminderSession(
    Guid Id,
    string Title,
    string JoinLink,
    DateTime ScheduledAt,
    string NotificationMode);

public sealed class SendOneHourReminderHandler(
    NpgsqlDataSource dataSource,
    DirectSessionNotificationSender directSender,
    ILogger<SendOneHourReminderHandler> logger) : ISendOneHourReminderHandler
{
    public async Task HandleAsync(Guid sessionId, CancellationToken ct)
    {
        await using var connection = await dataSource.OpenConnectionAsync(ct);

        var session = await connection.QuerySingleOrDefaultAsync<OneHourReminderSession>(
            """
            SELECT id,
                   title,
                   join_link AS JoinLink,
                   scheduled_at AS ScheduledAt,
                   notification_mode AS NotificationMode
            FROM sessions
            WHERE id = @SessionId
              AND status IN (@Confirmed, @ConfirmationSent)
              AND one_hour_reminder_processed_at IS NULL
            """,
            new
            {
                SessionId = sessionId,
                Confirmed = SessionStatus.Confirmed,
                ConfirmationSent = SessionStatus.ConfirmationSent
            });

        if (session is null)
        {
            logger.LogWarning("Session {SessionId} not eligible for one-hour reminder", sessionId);
            return;
        }

        var recipients = (await connection.QueryAsync<DirectNotificationRecipient>(
            """
            SELECT p.telegram_id AS TelegramId,
                   p.display_name AS DisplayName
            FROM session_participants sp
            JOIN players p ON p.id = sp.player_id
            WHERE sp.session_id = @SessionId
              AND sp.is_gm = false
              AND sp.registration_status = @Active
              AND sp.rsvp_status != @Declined
            """,
            new
            {
                SessionId = sessionId,
                Active = ParticipantRegistrationStatus.Active,
                Declined = RsvpStatus.Declined
            })).ToList();

        var mode = SessionNotificationModeExtensions.FromDatabaseValue(session.NotificationMode);
        if (mode.ShouldSendDirectMessages() && recipients.Count > 0)
        {
            var text = $"""
                ⏰ <b>Игра начнётся примерно через 1 час</b>

                📌 <b>{System.Net.WebUtility.HtmlEncode(session.Title)}</b>
                📅 {session.ScheduledAt.FormatMoscow()} (МСК)
                🔗 {System.Net.WebUtility.HtmlEncode(session.JoinLink)}
                """;

            await directSender.SendAsync(recipients, text, "one-hour-reminder", session.Id, ct);
        }

        await connection.ExecuteAsync(
            """
            UPDATE sessions
            SET one_hour_reminder_processed_at = now(),
                updated_at = now()
            WHERE id = @SessionId
              AND one_hour_reminder_processed_at IS NULL
            """,
            new { SessionId = sessionId });

        logger.LogInformation(
            "One-hour reminder processed for session {SessionId} ({Title}) with mode {NotificationMode}",
            sessionId,
            session.Title,
            session.NotificationMode);
    }
}
