using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using WorkClub.Api.Services;
using WorkClub.Application.Tasks.DTOs;

namespace WorkClub.Api.Endpoints.Tasks;

public static class TaskEndpoints
{
    public static void MapTaskEndpoints(this IEndpointRouteBuilder app)
    {
        var group = app.MapGroup("/api/tasks");

        group.MapGet("", GetTasks)
            .RequireAuthorization("RequireMember")
            .WithName("GetTasks");

        group.MapGet("{id:guid}", GetTask)
            .RequireAuthorization("RequireMember")
            .WithName("GetTask");

        group.MapPost("", CreateTask)
            .RequireAuthorization("RequireManager")
            .WithName("CreateTask");

        group.MapPatch("{id:guid}", UpdateTask)
            .RequireAuthorization("RequireMember")
            .WithName("UpdateTask");

        group.MapDelete("{id:guid}", DeleteTask)
            .RequireAuthorization("RequireManager")
            .WithName("DeleteTask");

        group.MapPost("{id:guid}/assign", AssignTaskToMe)
            .RequireAuthorization("RequireMember")
            .WithName("AssignTaskToMe");

        group.MapDelete("{id:guid}/assign", UnassignTaskFromMe)
            .RequireAuthorization("RequireMember")
            .WithName("UnassignTaskFromMe");
    }

    private static async Task<Ok<TaskListDto>> GetTasks(
        TaskService taskService,
        HttpContext httpContext,
        [FromQuery] string? status = null,
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20)
    {
        var externalUserId = httpContext.User.FindFirst("sub")?.Value;
        var result = await taskService.GetTasksAsync(status, page, pageSize, externalUserId);
        return TypedResults.Ok(result);
    }

    private static async Task<Results<Ok<TaskDetailDto>, NotFound>> GetTask(
        Guid id,
        TaskService taskService,
        HttpContext httpContext)
    {
        var externalUserId = httpContext.User.FindFirst("sub")?.Value;
        var result = await taskService.GetTaskByIdAsync(id, externalUserId);

        if (result == null)
            return TypedResults.NotFound();

        return TypedResults.Ok(result);
    }

    private static async Task<Results<Created<TaskDetailDto>, BadRequest<string>>> CreateTask(
        CreateTaskRequest request,
        TaskService taskService,
        HttpContext httpContext)
    {
        var userIdClaim = httpContext.User.FindFirst("sub")?.Value;
        if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out var createdById))
        {
            return TypedResults.BadRequest("Invalid user ID");
        }

        var (task, error) = await taskService.CreateTaskAsync(request, createdById);

        if (error != null || task == null)
            return TypedResults.BadRequest(error ?? "Failed to create task");

        return TypedResults.Created($"/api/tasks/{task.Id}", task);
    }

    private static async Task<Results<Ok<TaskDetailDto>, NotFound, UnprocessableEntity<string>, Conflict<string>>> UpdateTask(
        Guid id,
        UpdateTaskRequest request,
        TaskService taskService,
        HttpContext httpContext)
    {
        var externalUserId = httpContext.User.FindFirst("sub")?.Value;
        var (task, error, isConflict) = await taskService.UpdateTaskAsync(id, request, externalUserId);

        if (error != null)
        {
            if (error == "Task not found")
                return TypedResults.NotFound();

            if (isConflict)
                return TypedResults.Conflict(error);

            return TypedResults.UnprocessableEntity(error);
        }

        return TypedResults.Ok(task!);
    }

    private static async Task<Results<NoContent, NotFound>> DeleteTask(
        Guid id,
        TaskService taskService)
    {
        var deleted = await taskService.DeleteTaskAsync(id);

        if (!deleted)
            return TypedResults.NotFound();

        return TypedResults.NoContent();
    }

    private static async Task<Results<Ok, BadRequest<string>, NotFound>> AssignTaskToMe(
        Guid id,
        TaskService taskService,
        HttpContext httpContext)
    {
        var externalUserId = httpContext.User.FindFirst("sub")?.Value;
        if (externalUserId == null) return TypedResults.BadRequest("Invalid user");

        var (success, error) = await taskService.AssignToMeAsync(id, externalUserId);

        if (!success)
        {
            if (error == "Task not found") return TypedResults.NotFound();
            return TypedResults.BadRequest(error ?? "Failed to assign task");
        }

        return TypedResults.Ok();
    }

    private static async Task<Results<Ok, BadRequest<string>, NotFound>> UnassignTaskFromMe(
        Guid id,
        TaskService taskService,
        HttpContext httpContext)
    {
        var externalUserId = httpContext.User.FindFirst("sub")?.Value;
        if (externalUserId == null) return TypedResults.BadRequest("Invalid user");

        var (success, error) = await taskService.UnassignFromMeAsync(id, externalUserId);

        if (!success)
        {
            if (error == "Task not found") return TypedResults.NotFound();
            return TypedResults.BadRequest(error ?? "Failed to unassign task");
        }

        return TypedResults.Ok();
    }
}
