using ASTRAIN.Api.Data;
using ASTRAIN.Api.Services;
using ASTRAIN.Shared.Dtos;
using ASTRAIN.Shared.Models;
using ASTRAIN.Shared.Requests;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace ASTRAIN.Api.Endpoints;

/// <summary>
/// Provides exercise-related endpoints.
/// </summary>
internal static class ExerciseEndpoints
{
    /// <summary>
    /// Registers exercise routes under the provided route group.
    /// </summary>
    /// <param name="group">The API route group.</param>
    /// <returns>The same route group for chaining.</returns>
    public static RouteGroupBuilder MapExerciseEndpoints(this RouteGroupBuilder group)
    {
        group.MapGet("/users/{userId}/exercises", async (string userId, AppDbContext db, IConfiguration config) =>
            {
                var populateSampleData = config.GetValue("SampleData:Enabled", false);
                var user = await UserProvisioning.EnsureUserAsync(db, userId, populateSampleData);
                var items = await db.Exercises
                    .Where(e => e.UserId == user.Id)
                    .OrderBy(e => e.Name)
                    .Select(e => new ExerciseDto(e.Id, e.Name))
                    .ToListAsync();
                return Results.Ok(items);
            })
            .WithSummary("List exercises")
            .WithDescription("Returns the exercises for the specified user.");

        group.MapPost("/users/{userId}/exercises", async (string userId, ExerciseUpsertRequest request, AppDbContext db, IConfiguration config) =>
            {
                var populateSampleData = config.GetValue("SampleData:Enabled", false);
                var user = await UserProvisioning.EnsureUserAsync(db, userId, populateSampleData);
                if (string.IsNullOrWhiteSpace(request.Name))
                {
                    return Results.BadRequest("Name is required.");
                }

                var exercise = new Exercise
                {
                    Name = request.Name.Trim(),
                    UserId = user.Id
                };

                db.Exercises.Add(exercise);
                await db.SaveChangesAsync();

                return Results.Ok(new ExerciseDto(exercise.Id, exercise.Name));
            })
            .WithSummary("Create exercise")
            .WithDescription("Creates a new exercise for the specified user.");

        group.MapPut("/users/{userId}/exercises/{exerciseId:int}", async (string userId, int exerciseId, ExerciseUpsertRequest request, AppDbContext db, IConfiguration config) =>
            {
                var populateSampleData = config.GetValue("SampleData:Enabled", false);
                var user = await UserProvisioning.EnsureUserAsync(db, userId, populateSampleData);
                var exercise = await db.Exercises.FirstOrDefaultAsync(e => e.Id == exerciseId && e.UserId == user.Id);
                if (exercise is null)
                {
                    return Results.NotFound();
                }

                if (string.IsNullOrWhiteSpace(request.Name))
                {
                    return Results.BadRequest("Name is required.");
                }

                exercise.Name = request.Name.Trim();
                await db.SaveChangesAsync();

                return Results.Ok(new ExerciseDto(exercise.Id, exercise.Name));
            })
            .WithSummary("Update exercise")
            .WithDescription("Updates the name of an exercise for the specified user.");

        group.MapDelete("/users/{userId}/exercises/{exerciseId:int}", async (string userId, int exerciseId, AppDbContext db, IConfiguration config) =>
            {
                var populateSampleData = config.GetValue("SampleData:Enabled", false);
                var user = await UserProvisioning.EnsureUserAsync(db, userId, populateSampleData);
                var exercise = await db.Exercises.FirstOrDefaultAsync(e => e.Id == exerciseId && e.UserId == user.Id);
                if (exercise is null)
                {
                    return Results.NotFound();
                }

                db.Exercises.Remove(exercise);
                await db.SaveChangesAsync();

                return Results.NoContent();
            })
            .WithSummary("Delete exercise")
            .WithDescription("Deletes an exercise for the specified user.");

        return group;
    }
}
