using GmRelay.DiscordBot.Rendering;
using NetCord;
using NetCord.Rest;
using NetCord.Services.ApplicationCommands;

namespace GmRelay.DiscordBot.Features.Sessions;

public class DiscordNewSessionCommand : ApplicationCommandModule<SlashCommandContext>
{
    private readonly DiscordNewSessionHandler _handler;
    private readonly ILogger<DiscordNewSessionCommand> _logger;

    public DiscordNewSessionCommand(DiscordNewSessionHandler handler, ILogger<DiscordNewSessionCommand> logger)
    {
        _handler = handler;
        _logger = logger;
    }

    [SlashCommand("newsession", "Create a new game session")]
    public async Task ExecuteAsync(
        [SlashCommandParameter(Name = "title", Description = "Game title")] string title,
        [SlashCommandParameter(Name = "time", Description = "Session time (YYYY-MM-DD HH:mm or DD.MM.YYYY HH:mm)")] string time,
        [SlashCommandParameter(Name = "seats", Description = "Maximum number of players")] long? seats = null,
        [SlashCommandParameter(Name = "link", Description = "Join link")] string? link = null)
    {
        _logger.LogInformation(
            "newsession called by user {UserId} ({UserType}) in guild {GuildId}, channel {ChannelId}",
            Context.User.Id,
            Context.User.GetType().Name,
            Context.Interaction.GuildId,
            Context.Channel?.Id);

        var guildId = Context.Interaction.GuildId
            ?? throw new InvalidOperationException("This command can only be used in a guild.");

        var member = Context.User as GuildInteractionUser;
        if (member is null)
        {
            _logger.LogError("Context.User is not GuildInteractionUser. Actual type: {ActualType}", Context.User.GetType().Name);
            throw new InvalidOperationException("Guild member data not available in interaction.");
        }

        var resolvedPermissions = (ulong)member.Permissions;
        _logger.LogInformation("Resolved permissions for user {UserId}: {Permissions}", Context.User.Id, resolvedPermissions);

        ulong guildOwnerId = 0;
        var guildName = guildId.ToString();
        try
        {
            var guild = await Context.Client.Rest.GetGuildAsync(guildId);
            guildOwnerId = guild.OwnerId;
            guildName = guild.Name;
            _logger.LogInformation("Guild owner id: {OwnerId}", guildOwnerId);
        }
        catch (RestException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
        {
            _logger.LogWarning(
                ex,
                "Bot is not a REST member of guild {GuildId}; using resolved permissions from interaction payload",
                guildId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unexpected error fetching guild {GuildId}", guildId);
        }

        var timeResult = DiscordNewSessionHandler.ParseTimeInput(time);
        if (!timeResult.IsSuccess)
        {
            await Context.Interaction.SendResponseAsync(
                InteractionCallback.Message($"X {timeResult.Error}"));
            return;
        }

        // Defer the response to avoid Discord 3-second interaction timeout
        await Context.Interaction.SendResponseAsync(InteractionCallback.DeferredMessage());

        try
        {
            _logger.LogInformation("Creating session for guild {GuildId}, user {UserId}", guildId, Context.User.Id);

            var view = await _handler.HandleAsync(
                guildId: guildId.ToString(),
                channelId: Context.Channel!.Id.ToString(),
                groupName: guildName,
                userId: Context.User.Id,
                userDisplayName: Context.User.GlobalName ?? Context.User.Username,
                resolvedPermissions: resolvedPermissions,
                guildOwnerId: guildOwnerId,
                title: title,
                scheduledAt: timeResult.Value,
                maxPlayers: seats is null ? null : (int)seats.Value,
                joinLink: link,
                CancellationToken.None);

            _logger.LogInformation("Session created successfully. Building render.");

            var (embeds, actionRows) = DiscordSessionBatchRenderer.Render(view);

            _logger.LogInformation("Sending success response.");

            await Context.Interaction.ModifyResponseAsync(message =>
            {
                message.Content = ":white_check_mark: **Session created successfully!**";
                message.Embeds = embeds;
                message.Components = actionRows;
            });

            _logger.LogInformation("Success response sent.");
        }
        catch (UnauthorizedAccessException ex)
        {
            _logger.LogWarning(ex, "Unauthorized session creation attempt by user {UserId}", Context.User.Id);
            await Context.Interaction.ModifyResponseAsync(message =>
            {
                message.Content = $":no_entry: {ex.Message}";
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to create session for user {UserId} in guild {GuildId}", Context.User.Id, guildId);
            await Context.Interaction.ModifyResponseAsync(message =>
            {
                message.Content = ":boom: An error occurred while creating the session.";
            });
        }
    }
}
