using Microsoft.AspNetCore.Mvc; using Nexus.Api.Data; using Nexus.Api.DTOs; using Nexus.Api.Repositories; namespace Nexus.Api.Controllers; [ApiController] [Route("api/v1/projects")] public class ProjectsController(IProjectRepository projectRepo, IActivityRepository activityRepo) : ControllerBase { [HttpGet] public async Task GetAll(CancellationToken ct) => Results.Ok(await projectRepo.GetAllAsync(ct)); [HttpPost] public async Task Create([FromBody] CreateProjectRequest request, CancellationToken ct) { if (string.IsNullOrWhiteSpace(request.Name)) return Results.ValidationProblem(new Dictionary { ["name"] = ["Name is required."] }); var project = new Project { Name = request.Name.Trim(), Description = request.Description?.Trim() ?? string.Empty, Status = OperationalStatus.Online }; await projectRepo.AddAsync(project, ct); await activityRepo.AddAsync(new ActivityEvent { Type = "project", Message = $"Project {project.Name} created" }, ct); return Results.Created($"/api/v1/projects/{project.Id}", project); } [HttpGet("{id:guid}")] public async Task GetById(Guid id, CancellationToken ct) { var project = await projectRepo.GetByIdAsync(id, ct); return project is null ? Results.NotFound() : Results.Ok(project); } [HttpPatch("{id:guid}")] public async Task Update(Guid id, [FromBody] UpdateProjectRequest request, CancellationToken ct) { var project = await projectRepo.GetByIdAsync(id, ct); if (project is null) return Results.NotFound(); if (!string.IsNullOrWhiteSpace(request.Name)) project.Name = request.Name.Trim(); if (request.Description is not null) project.Description = request.Description.Trim(); if (!string.IsNullOrWhiteSpace(request.Status) && Enum.TryParse(request.Status, true, out var parsedStatus)) project.Status = parsedStatus; await projectRepo.UpdateAsync(project, ct); await activityRepo.AddAsync(new ActivityEvent { Type = "project", Message = $"Project {project.Name} updated" }, ct); return Results.Ok(project); } [HttpDelete("{id:guid}")] public async Task Delete(Guid id, CancellationToken ct) { var project = await projectRepo.GetByIdAsync(id, ct); if (project is null) return Results.NotFound(); var hasTasks = await projectRepo.HasTasksAsync(id, ct); if (hasTasks) { project.Status = OperationalStatus.Offline; await projectRepo.UpdateAsync(project, ct); await activityRepo.AddAsync(new ActivityEvent { Type = "project", Message = $"Project {project.Name} archived" }, ct); return Results.Ok(project); } await projectRepo.DeleteAsync(project, ct); await activityRepo.AddAsync(new ActivityEvent { Type = "project", Message = $"Project {project.Name} deleted" }, ct); return Results.NoContent(); } }