using Dapper;
using FastEndpoints;
using KBX.Shared.Experience;
using Npgsql;

namespace KBX.Modules.Common.Suggestions.Submit;

public sealed record Request(
    string Category,
    string Message,
    bool IncludeScreenContext,
    SuggestionContext Context);

public sealed record Response(Guid SuggestionId, DateTimeOffset ReceivedAt);

public sealed class Endpoint(NpgsqlDataSource dataSource) : Endpoint<Request, Response>
{
    public override void Configure()
    {
        Post("/api/common/suggestions");
        Permissions("common.suggestion.create");
    }

    public override async Task HandleAsync(Request req, CancellationToken ct)
    {
        if (req.Message.Trim().Length is < 3 or > 2000)
        {
            AddError(r => r.Message, "의견 내용은 3~2000자로 입력하세요.");
            await Send.ErrorsAsync(cancellation: ct);
            return;
        }

        if (req.Category is not ("inconvenience" or "bug" or "improvement"))
        {
            AddError(r => r.Category, "지원하지 않는 의견 유형입니다.");
            await Send.ErrorsAsync(cancellation: ct);
            return;
        }

        // Host application must replace these claims adapters with its authenticated tenant/user resolver.
        var tenantId = Guid.Empty;
        var userId = Guid.Empty;
        var id = Guid.NewGuid();
        var now = DateTimeOffset.UtcNow;

        object? context = null;
        if (req.IncludeScreenContext)
        {
            // Deliberately persist diagnostic keys only, not arbitrary screen/business values.
            context = new
            {
                req.Context.ActiveFilters,
                req.Context.GridLayoutVersion,
            };
        }

        await using var connection = await dataSource.OpenConnectionAsync(ct);
        await connection.ExecuteAsync(new CommandDefinition("""
            insert into kbx.user_suggestions
                (id, tenant_id, user_id, category, message, screen_id, screen_version,
                 route, app_version, user_role, context, status, created_at)
            values
                (@Id, @TenantId, @UserId, @Category, @Message, @ScreenId, @ScreenVersion,
                 @Route, @AppVersion, @UserRole, cast(@Context as jsonb), 'NEW', @CreatedAt)
            """, new
        {
            Id = id,
            TenantId = tenantId,
            UserId = userId,
            req.Category,
            Message = req.Message.Trim(),
            req.Context.ScreenId,
            req.Context.ScreenVersion,
            req.Context.Route,
            req.Context.AppVersion,
            req.Context.UserRole,
            Context = context is null ? null : System.Text.Json.JsonSerializer.Serialize(context),
            CreatedAt = now,
        }, cancellationToken: ct));

        await Send.OkAsync(new Response(id, now), ct);
    }
}
