using Health.Application.Exercises;

namespace Health.WebApi.Endpoints;

public static class ExerciseEndpoints
{
    public static void MapExerciseEndpoints(this WebApplication app)
    {
        var group = app.MapGroup("/api/exercise-plans").RequireAuthorization();

        group.MapGet("/current", async (HttpContext http, IExerciseService exercises, CancellationToken ct) =>
        {
            var userId = GetUserId(http);
            var plan = await exercises.GetCurrentAsync(userId, ct);
            return Results.Ok(new { code = 0, data = plan, message = (string?)null });
        });

        group.MapPost("/", async (HttpRequest request, HttpContext http, IExerciseService exercises, CancellationToken ct) =>
        {
            var userId = GetUserId(http);
            var body = await ReadBodyAsync(request, ct);
            using var json = JsonDocument.Parse(body);
            var root = json.RootElement;

            var exerciseType = root.TryGetProperty("exerciseType", out var et) ? et.GetString() : "运动";
            var duration = root.TryGetProperty("durationMinutes", out var dm) ? dm.GetInt32() : 30;
            var startDate = DateOnly.Parse(root.TryGetProperty("startDate", out var sd)
                ? sd.GetString()!
                : DateTime.UtcNow.AddHours(8).ToString("yyyy-MM-dd"));
            var endDate = DateOnly.Parse(root.TryGetProperty("endDate", out var ed)
                ? ed.GetString()!
                : DateTime.UtcNow.AddHours(8).AddDays(6).ToString("yyyy-MM-dd"));
            var reminderTime = root.TryGetProperty("reminderTime", out var rt) && TimeOnly.TryParse(rt.GetString(), out var parsedTime)
                ? parsedTime
                : new TimeOnly(19, 0);

            var planId = await exercises.CreateAsync(userId, new ExercisePlanCreateRequest(startDate, endDate, exerciseType, duration, reminderTime), ct);
            return Results.Ok(new { code = 0, data = new { id = planId }, message = (string?)null });
        });

        group.MapGet("/", async (HttpContext http, IExerciseService exercises, CancellationToken ct) =>
        {
            var userId = GetUserId(http);
            var plans = await exercises.ListAsync(userId, ct);
            return Results.Ok(new { code = 0, data = plans, message = (string?)null });
        });

        group.MapGet("/{id:guid}", async (Guid id, HttpContext http, IExerciseService exercises, CancellationToken ct) =>
        {
            var userId = GetUserId(http);
            var plan = await exercises.GetByIdAsync(userId, id, ct);
            if (plan == null) return Results.Ok(new { code = 40004, message = "不存在" });

            return Results.Ok(new { code = 0, data = plan, message = (string?)null });
        });

        group.MapDelete("/{id:guid}", async (Guid id, HttpContext http, IExerciseService exercises, CancellationToken ct) =>
        {
            var userId = GetUserId(http);
            await exercises.DeleteAsync(userId, id, ct);
            return Results.Ok(new { code = 0, data = new { success = true }, message = (string?)null });
        });

        group.MapPost("/items/{itemId:guid}/checkin", async (Guid itemId, HttpContext http, IExerciseService exercises, CancellationToken ct) =>
        {
            var userId = GetUserId(http);
            var completed = await exercises.ToggleCheckInAsync(userId, itemId, ct);
            if (completed == null) return Results.Ok(new { code = 40004, message = "不存在" });

            return Results.Ok(new { code = 0, data = new { completed }, message = (string?)null });
        });
    }

    private static async Task<string> ReadBodyAsync(HttpRequest request, CancellationToken ct)
    {
        request.EnableBuffering();
        using var reader = new StreamReader(request.Body, leaveOpen: true);
        var body = await reader.ReadToEndAsync(ct);
        request.Body.Position = 0;
        return string.IsNullOrWhiteSpace(body) ? "{}" : body;
    }

    private static Guid GetUserId(HttpContext http) =>
        Guid.TryParse(http.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value, out var id) ? id : Guid.Empty;
}
