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

namespace GmRelay.Bot.Features.Sessions.RescheduleSession;

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

public sealed record InitiateRescheduleCommand(
    Guid SessionId,
    long TelegramUserId,
    string CallbackQueryId,
    long ChatId,
    int? MessageThreadId,
    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,
    IPlatformMessenger messenger,
    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.platform = 'Telegram'
                         AND p.external_user_id = @ExternalUserId
                   ) AS CanManage
            FROM sessions s
            WHERE s.id = @SessionId AND s.status != @Cancelled
            """,
            new { command.SessionId, ExternalUserId = command.TelegramUserId.ToString(), Cancelled = SessionStatus.Cancelled });

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

        if (!session.CanManage)
        {
            await AnswerAsync(command.CallbackQueryId, "Только owner или co-GM может переносить сессию.", ct, showAlert: true);
            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 AnswerAsync(command.CallbackQueryId, "Уже есть активный запрос на перенос этой сессии.", ct, showAlert: true);
            return;
        }

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

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

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

        var prompt = string.Join(
            "\n",
            new[]
            {
                $"⏰ Укажите 2-3 варианта времени для сессии «{session.Title}» и дедлайн голосования.",
                "",
                "Формат:",
                "<code>25.04.2026 19:30",
                "26.04.2026 18:00",
                "Дедлайн: 25.04.2026 12:00</code>",
                "",
                "Дедлайн должен быть в будущем и раньше первого предложенного времени."
            });

        await messenger.SendGroupMessageAsync(
            TelegramPlatformIds.Group(command.ChatId, command.MessageThreadId),
            prompt,
            ct);
    }

    private Task AnswerAsync(string callbackQueryId, string text, CancellationToken ct, bool showAlert = false) =>
        messenger.AnswerInteractionAsync(new PlatformInteractionReply(callbackQueryId, text, showAlert), ct);
}
