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

namespace GmRelay.Bot.Features.Sessions.RescheduleSession;

// ── Command ──────────────────────────────────────────────────────────

public sealed record InitiateRescheduleCommand(
    Guid SessionId,
    long TelegramUserId,
    string CallbackQueryId,
    long ChatId,
    int MessageId);

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

internal sealed record RescheduleSessionInfoDto(string Title, bool CanManage);

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

/// <summary>
/// Handles the "⏰ Перенести" button press from the batch message.
/// Creates a reschedule proposal in AwaitingTime status and prompts
/// the GM to enter 2-3 new time options and a voting deadline.
/// </summary>
public sealed class InitiateRescheduleHandler(
    NpgsqlDataSource dataSource,
    ITelegramBotClient bot,
    ILogger<InitiateRescheduleHandler> logger)
{
    public async Task HandleAsync(InitiateRescheduleCommand command, CancellationToken ct)
    {
        await using var connection = await dataSource.OpenConnectionAsync(ct);

        // 1. Verify group management access.
        var session = await connection.QuerySingleOrDefaultAsync<RescheduleSessionInfoDto>(
            """
            SELECT s.title AS Title,
                   EXISTS (
                       SELECT 1
                       FROM group_managers gm
                       JOIN players p ON p.id = gm.player_id
                       WHERE gm.group_id = s.group_id
                         AND p.telegram_id = @TelegramUserId
                   ) AS CanManage
            FROM sessions s
            WHERE s.id = @SessionId AND s.status != @Cancelled
            """,
            new { command.SessionId, command.TelegramUserId, Cancelled = SessionStatus.Cancelled });

        if (session is null)
        {
            await bot.AnswerCallbackQuery(command.CallbackQueryId, "Сессия не найдена.", cancellationToken: ct);
            return;
        }

        if (!session.CanManage)
        {
            await bot.AnswerCallbackQuery(command.CallbackQueryId,
                "Только owner или co-GM может переносить сессию.", showAlert: true, cancellationToken: ct);
            return;
        }

        // 2. Check no active proposal exists
        var hasActive = await connection.ExecuteScalarAsync<bool>(
            """
            SELECT EXISTS (
                SELECT 1 FROM reschedule_proposals
                WHERE session_id = @SessionId AND status IN ('AwaitingTime', 'Voting')
            )
            """,
            new { command.SessionId });

        if (hasActive)
        {
            await bot.AnswerCallbackQuery(command.CallbackQueryId,
                "Уже есть активный запрос на перенос этой сессии.", showAlert: true, cancellationToken: ct);
            return;
        }

        // 3. Create proposal in AwaitingTime status
        await connection.ExecuteAsync(
            """
            INSERT INTO reschedule_proposals (session_id, proposed_by, status)
            VALUES (@SessionId, @GmId, 'AwaitingTime')
            """,
            new { command.SessionId, GmId = command.TelegramUserId });

        logger.LogInformation("Reschedule initiated for session {SessionId} by GM {GmId}", command.SessionId, command.TelegramUserId);

        // 4. Prompt GM in chat
        await bot.AnswerCallbackQuery(command.CallbackQueryId,
            "Введите 2-3 варианта времени и дедлайн голосования.", cancellationToken: ct);

        await bot.SendMessage(
            chatId: command.ChatId,
            text: $"""
                ⏰ Укажите 2-3 варианта времени для сессии «{session.Title}» и дедлайн голосования.

                Формат:
                <code>25.04.2026 19:30
                26.04.2026 18:00
                Дедлайн: 25.04.2026 12:00</code>

                Дедлайн должен быть в будущем и раньше первого предложенного времени.
                """,
            parseMode: Telegram.Bot.Types.Enums.ParseMode.Html,
            cancellationToken: ct);
    }
}
