using Microsoft.EntityFrameworkCore; using OtaFleet.Api.Data; using OtaFleet.Api.Data.Entities; namespace OtaFleet.Api.Endpoints; public static class AdminEndpoints { public static void MapAdminEndpoints(this IEndpointRouteBuilder app) { var group = app.MapGroup("/api/admin"); // Vehicles group.MapGet("/vehicles", async (OtaDbContext db) => { return await db.Vehicles.Include(v => v.Group).ToListAsync(); }); // Groups group.MapGet("/groups", async (OtaDbContext db) => { return await db.VehicleGroups.Include(g => g.Vehicles).ToListAsync(); }); group.MapPost("/groups", async (OtaDbContext db, CreateGroupRequest request) => { var group = new VehicleGroup { Name = request.Name, Description = request.Description }; db.VehicleGroups.Add(group); await db.SaveChangesAsync(); return Results.Created($"/api/admin/groups/{group.Id}", group); }); group.MapPut("/groups/{id}", async (OtaDbContext db, int id, UpdateGroupRequest request) => { var group = await db.VehicleGroups.FindAsync(id); if (group == null) return Results.NotFound(); group.Name = request.Name; group.Description = request.Description; await db.SaveChangesAsync(); return Results.Ok(group); }); group.MapPost("/groups/{groupId}/vehicles", async (OtaDbContext db, int groupId, AssignVehicleRequest request) => { var vehicle = await db.Vehicles.FindAsync(request.Vin); if (vehicle == null) return Results.NotFound("Vehicle not found"); var group = await db.VehicleGroups.FindAsync(groupId); if (group == null) return Results.NotFound("Group not found"); vehicle.GroupId = groupId; await db.SaveChangesAsync(); return Results.Ok(); }); // Updates group.MapPost("/updates", async (OtaDbContext db, HttpRequest request) => { if (!request.HasFormContentType) return Results.BadRequest("Expected multipart/form-data"); var form = await request.ReadFormAsync(); var file = form.Files["file"]; var version = form["version"]; var description = form["description"]; if (file == null || file.Length == 0) return Results.BadRequest("No file uploaded"); if (string.IsNullOrEmpty(version)) return Results.BadRequest("Version is required"); // Save file var uploadsDir = Path.Combine(Directory.GetCurrentDirectory(), "uploads"); Directory.CreateDirectory(uploadsDir); var filePath = Path.Combine(uploadsDir, $"{version}_{file.FileName}"); using (var stream = new FileStream(filePath, FileMode.Create)) { await file.CopyToAsync(stream); } var update = new FirmwareUpdate { Version = version!, Description = description, FilePath = filePath, UploadedAt = DateTime.UtcNow }; db.FirmwareUpdates.Add(update); await db.SaveChangesAsync(); return Results.Ok(update); }); group.MapGet("/updates", async (OtaDbContext db) => { return await db.FirmwareUpdates.OrderByDescending(u => u.UploadedAt).ToListAsync(); }); // Deployments group.MapPost("/deployments", async (OtaDbContext db, CreateDeploymentRequest request) => { var update = await db.FirmwareUpdates.FindAsync(request.UpdateId); if (update == null) return Results.NotFound("Update not found"); var deployment = new Deployment { UpdateId = request.UpdateId, TargetVin = request.TargetVin, TargetGroupId = request.TargetGroupId, Status = "Pending", CreatedAt = DateTime.UtcNow }; db.Deployments.Add(deployment); await db.SaveChangesAsync(); return Results.Created($"/api/admin/deployments/{deployment.Id}", deployment); }); group.MapGet("/deployments", async (OtaDbContext db) => { return await db.Deployments .Include(d => d.Update) .OrderByDescending(d => d.CreatedAt) .ToListAsync(); }); } } public record CreateGroupRequest(string Name, string? Description); public record UpdateGroupRequest(string Name, string? Description); public record AssignVehicleRequest(string Vin); public record CreateDeploymentRequest(int UpdateId, string? TargetVin, int? TargetGroupId);