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, AppDbContext db) =>
        {
            var userId = GetUserId(http);
            var today = DateOnly.FromDateTime(DateTime.Now);
            var monday = today.AddDays(-(int)today.DayOfWeek + 1);
            var plan = await db.ExercisePlans.Include(p => p.Items).FirstOrDefaultAsync(p => p.UserId == userId && p.WeekStartDate == monday);
            if (plan == null) return Results.Ok(new { code = 0, data = (object?)null, message = (string?)null });
            return Results.Ok(new
            {
                code = 0,
                data = new
                {
                    plan.Id, plan.WeekStartDate, plan.CreatedAt, plan.UpdatedAt,
                    items = plan.Items.Select(i => new
                    {
                        i.Id, i.DayOfWeek,
                        i.ExerciseType, i.DurationMinutes,
                        i.IsCompleted, i.CompletedAt, i.IsRestDay
                    })
                },
                message = (string?)null
            });
        });

        group.MapPost("/", async (HttpRequest request, HttpContext http, AppDbContext db, CancellationToken ct) =>
        {
            var userId = GetUserId(http);
            request.EnableBuffering();
            using var reader = new StreamReader(request.Body);
            var body = await reader.ReadToEndAsync(ct);
            request.Body.Position = 0;
            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.Now.ToString("yyyy-MM-dd")));
            var endDate = DateOnly.Parse((root.TryGetProperty("endDate", out var ed) ? ed.GetString()! : DateTime.Now.AddDays(6).ToString("yyyy-MM-dd")));
            var plan = new ExercisePlan { Id = Guid.NewGuid(), UserId = userId, WeekStartDate = startDate };
            for (var d = startDate; d <= endDate; d = d.AddDays(1))
            {
                plan.Items.Add(new ExercisePlanItem
                {
                    Id = Guid.NewGuid(),
                    DayOfWeek = (int)d.DayOfWeek,
                                        ExerciseType = exerciseType,
                    DurationMinutes = duration,
                    IsRestDay = false,
                });
            }
            db.ExercisePlans.Add(plan);
            await db.SaveChangesAsync(ct);
            return Results.Ok(new { code = 0, data = new { plan.Id }, message = (string?)null });
        });

        group.MapGet("/", async (HttpContext http, AppDbContext db) =>
        {
            var userId = GetUserId(http);
            var plans = await db.ExercisePlans.Where(p => p.UserId == userId)
                .OrderByDescending(p => p.WeekStartDate).Take(20)
                .Select(p => new
                {
                    p.Id, p.WeekStartDate, p.CreatedAt,
                    totalDays = p.Items.Count,
                    completedDays = p.Items.Count(i => i.IsCompleted),
                    items = p.Items.OrderBy(i => i.DayOfWeek).Select(i => new
                    {
                        i.Id, i.DayOfWeek,
                        i.ExerciseType, i.DurationMinutes,
                        i.IsCompleted, i.IsRestDay
                    })
                }).ToListAsync();
            return Results.Ok(new { code = 0, data = plans, message = (string?)null });
        });

        group.MapGet("/{id:guid}", async (Guid id, HttpContext http, AppDbContext db) =>
        {
            var userId = GetUserId(http);
            var plan = await db.ExercisePlans.Include(p => p.Items)
                .FirstOrDefaultAsync(p => p.Id == id && p.UserId == userId);
            if (plan == null) return Results.Ok(new { code = 40004, message = "不存在" });
            return Results.Ok(new
            {
                code = 0,
                data = new
                {
                    plan.Id, plan.WeekStartDate, plan.CreatedAt,
                    items = plan.Items.OrderBy(i => i.DayOfWeek).Select(i => new
                    {
                        i.Id, i.DayOfWeek, i.ExerciseType, i.DurationMinutes,
                        i.IsCompleted, i.CompletedAt, i.IsRestDay
                    })
                },
                message = (string?)null
            });
        });

        group.MapDelete("/{id:guid}", async (Guid id, HttpContext http, AppDbContext db, CancellationToken ct) =>
        {
            var userId = GetUserId(http);
            var plan = await db.ExercisePlans.Include(p => p.Items).FirstOrDefaultAsync(p => p.Id == id && p.UserId == userId, ct);
            if (plan != null) { db.ExercisePlans.Remove(plan); await db.SaveChangesAsync(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, AppDbContext db, CancellationToken ct) =>
        {
            var item = await db.ExercisePlanItems.FindAsync([itemId], ct);
            if (item == null) return Results.Ok(new { code = 40004, message = "不存在" });
            item.IsCompleted = !item.IsCompleted;
            item.CompletedAt = item.IsCompleted ? DateTime.UtcNow : null;
            await db.SaveChangesAsync(ct);
            return Results.Ok(new { code = 0, data = new { completed = item.IsCompleted }, message = (string?)null });
        });
    }

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

