using Knot.Shared.Kernel;
using Knot.Modules.Profiles.Application.Profiles.Avatar;
using Knot.Modules.Profiles.Application.Profiles.GetProfile;
using Knot.Modules.Profiles.Application.Profiles.Search;
using Knot.Modules.Profiles.Application.Profiles.UpdateProfile;
using Knot.Modules.Profiles.Application.Profiles.UpdateSettings;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Mvc;

namespace Knot.Modules.Profiles.Presentation.Endpoints;

public static class ProfilesEndpoints
{
    public static void MapProfilesEndpoints(this WebApplication app)
    {
        var group = app.MapGroup("api/profiles").RequireAuthorization();

        group.MapGet("search", async ([FromQuery] string q, ISender sender, IUserContext userContext, CancellationToken ct) =>
        {
            var result = await sender.Send(new SearchProfilesQuery(q, userContext.UserId), ct);
            return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error);
        });

        group.MapPut("settings", async ([FromBody] Knot.Modules.Profiles.Application.Profiles.DTOs.UpdateSettingsRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
        {
            var result = await sender.Send(new UpdateSettingsCommand(userContext.UserId, request.HideStoryViews), ct);
            return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound(result.Error);
        });

        group.MapPost("avatar", async (HttpRequest req, ISender sender, IUserContext userContext, CancellationToken ct) =>
        {
            if (!req.HasFormContentType) return Results.BadRequest("No file uploaded");
            var form = await req.ReadFormAsync(ct);
            var file = form.Files.FirstOrDefault();
            if (file == null || file.Length == 0) return Results.BadRequest("No file uploaded");

            using var stream = file.OpenReadStream();
            var result = await sender.Send(new UploadAvatarCommand(userContext.UserId, stream, file.FileName, file.ContentType), ct);
            return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound(result.Error);
        }).DisableAntiforgery();

        group.MapPost("avatar/crop", async (HttpRequest req, ISender sender, IUserContext userContext, CancellationToken ct) =>
        {
            if (!req.HasFormContentType) return Results.BadRequest("No file uploaded");
            var form = await req.ReadFormAsync(ct);
            var file = form.Files.FirstOrDefault();
            if (file == null || file.Length == 0) return Results.BadRequest("No file uploaded");

            int.TryParse(form["x"], out int x);
            int.TryParse(form["y"], out int y);
            int.TryParse(form["width"], out int width);
            int.TryParse(form["height"], out int height);
            int.TryParse(form["sw"], out int sw);
            int.TryParse(form["sh"], out int sh);

            using var stream = file.OpenReadStream();
            var result = await sender.Send(new CropAvatarCommand(userContext.UserId, stream, file.FileName ?? "avatar.jpg", file.ContentType, x, y, width, height, sw, sh), ct);
            return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound(result.Error);
        }).DisableAntiforgery();

        group.MapDelete("avatar", async (ISender sender, IUserContext userContext, CancellationToken ct) =>
        {
            var result = await sender.Send(new DeleteAvatarCommand(userContext.UserId), ct);
            return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound(result.Error);
        });

        group.MapPut("profile", async ([FromBody] Knot.Modules.Profiles.Application.Profiles.DTOs.UpdateProfileRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
        {
            var result = await sender.Send(new UpdateProfileCommand(userContext.UserId, request.DisplayName, request.Bio, request.Birthday), ct);
            return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound(result.Error);
        });

        group.MapGet("{id:guid}", async (Guid id, ISender sender, CancellationToken ct) =>
        {
            var result = await sender.Send(new GetProfileQuery(id), ct);
            return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound(result.Error);
        });
    }
}
