using Knot.Contracts.Relations.Domain;
using Knot.Modules.Relations.Application.Contacts;
using Knot.Shared.Infrastructure;
using Knot.Shared.Kernel;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore;

namespace Knot.Modules.Relations.Presentation.Endpoints;

public static class ContactsEndpoints
{
    public static void MapContactsEndpoints(this WebApplication app)
    {
        var group = app.MapGroup("api/contacts").RequireAuthorization();

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

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

        group.MapGet("status/{userId:guid}", async ([FromRoute] Guid userId, ISender sender, IUserContext userContext, [FromServices] IContactsDbContext context, CancellationToken ct) =>
        {
            var contact = await context.Contacts
                .FirstOrDefaultAsync(c =>
                    (c.UserId == userContext.UserId && c.ContactId == userId) ||
                    (c.UserId == userId && c.ContactId == userContext.UserId), ct);

            if (contact == null)
            {
                return Results.Ok(new { status = "none", friendshipId = (string?)null });
            }

            string status;
            string? friendshipId = contact.Id.ToString();

            if (contact.UserId == userContext.UserId && contact.Status == ContactStatus.Pending)
            {
                status = "outgoing";
            }
            else if (contact.Status == ContactStatus.Pending)
            {
                status = "pending";
            }
            else if (contact.Status == ContactStatus.Accepted)
            {
                status = "accepted";
            }
            else if (contact.Status == ContactStatus.Declined)
            {
                status = "declined";
            }
            else
            {
                status = "none";
            }

            return Results.Ok(new { status, friendshipId });
        });

        group.MapPost("request", async ([FromBody] SendContactRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
        {
            var result = await sender.Send(new SendContactRequestCommand(userContext.UserId, request.ContactId), ct);
            return result.IsSuccess ? Results.Ok(new { status = "pending" }) : Results.BadRequest(result.Error.Description);
        });

        group.MapPost("{id:guid}/accept", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
        {
            var result = await sender.Send(new AcceptContactRequestCommand(userContext.UserId, id), ct);
            return result.IsSuccess ? Results.Ok(new { id = result.Value }) : Results.NotFound(result.Error.Description);
        });

        group.MapPost("{id:guid}/decline", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
        {
            var result = await sender.Send(new DeclineContactRequestCommand(userContext.UserId, id), ct);
            return result.IsSuccess ? Results.Ok(new { success = true }) : Results.NotFound(result.Error.Description);
        });


        group.MapDelete("{id:guid}", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
        {
            var result = await sender.Send(new RemoveContactCommand(userContext.UserId, id), ct);
            return result.IsSuccess ? Results.Ok(new SuccessResponse(true)) : Results.NotFound(result.Error.Description);
        });
    }

    public record SendContactRequest(Guid ContactId);
}
