using Dapper;
using GmRelay.Shared.Domain;
using Npgsql;

namespace GmRelay.Bot.Infrastructure.Scheduling;

public interface ISessionTriggerStore
{
    Task<IReadOnlyList<Guid>> GetSessionsNeedingConfirmationAsync(DateTimeOffset now, CancellationToken ct);
    Task<IReadOnlyList<Guid>> GetSessionsNeedingOneHourReminderAsync(DateTimeOffset now, CancellationToken ct);
    Task<IReadOnlyList<Guid>> GetSessionsNeedingJoinLinkAsync(DateTimeOffset now, CancellationToken ct);
}

public sealed class DbSessionTriggerStore(NpgsqlDataSource dataSource) : ISessionTriggerStore
{
    private static readonly TimeSpan ConfirmationLeadTime = TimeSpan.FromHours(24);
    private static readonly TimeSpan OneHourReminderLeadTime = TimeSpan.FromHours(1);
    private static readonly TimeSpan JoinLinkLeadTime = TimeSpan.FromMinutes(5);

    public async Task<IReadOnlyList<Guid>> GetSessionsNeedingConfirmationAsync(DateTimeOffset now, CancellationToken ct)
    {
        await using var connection = await dataSource.OpenConnectionAsync(ct);

        var results = await connection.QueryAsync<Guid>(
            """
            SELECT id
            FROM sessions
            WHERE status = @Planned
              AND scheduled_at - @LeadTime <= @Now
              AND confirmation_sent_at IS NULL
            """,
            new
            {
                Planned = SessionStatus.Planned,
                LeadTime = ConfirmationLeadTime,
                Now = now.UtcDateTime
            });

        return results.ToList();
    }

    public async Task<IReadOnlyList<Guid>> GetSessionsNeedingOneHourReminderAsync(DateTimeOffset now, CancellationToken ct)
    {
        await using var connection = await dataSource.OpenConnectionAsync(ct);

        var results = await connection.QueryAsync<Guid>(
            """
            SELECT id
            FROM sessions
            WHERE status IN (@Confirmed, @ConfirmationSent)
              AND scheduled_at - @LeadTime <= @Now
              AND one_hour_reminder_processed_at IS NULL
            """,
            new
            {
                Confirmed = SessionStatus.Confirmed,
                ConfirmationSent = SessionStatus.ConfirmationSent,
                LeadTime = OneHourReminderLeadTime,
                Now = now.UtcDateTime
            });

        return results.ToList();
    }

    public async Task<IReadOnlyList<Guid>> GetSessionsNeedingJoinLinkAsync(DateTimeOffset now, CancellationToken ct)
    {
        await using var connection = await dataSource.OpenConnectionAsync(ct);

        var results = await connection.QueryAsync<Guid>(
            """
            SELECT id
            FROM sessions
            WHERE status = @Confirmed
              AND scheduled_at - @LeadTime <= @Now
              AND link_message_id IS NULL
            """,
            new
            {
                Confirmed = SessionStatus.Confirmed,
                LeadTime = JoinLinkLeadTime,
                Now = now.UtcDateTime
            });

        return results.ToList();
    }
}
