using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; using ProposalSystem.Application.DTOs; using ProposalSystem.Application.Interfaces; namespace ProposalSystem.Api.Controllers; [ApiController] [Route("api/proposals")] [Authorize] public class ProposalsController : ControllerBase { private readonly IProposalService _proposalService; private readonly IJobPublisher _jobPublisher; private readonly ISimilarProposalService _similarService; public ProposalsController( IProposalService proposalService, IJobPublisher jobPublisher, ISimilarProposalService similarService) { _proposalService = proposalService; _jobPublisher = jobPublisher; _similarService = similarService; } [HttpPost] [ProducesResponseType(typeof(ProposalResponse), 201)] [ProducesResponseType(400)] public async Task> Create( [FromBody] CreateProposalRequest request, CancellationToken ct) { var result = await _proposalService.CreateAsync(request, ct); return CreatedAtAction(nameof(GetById), new { id = result.Id }, result); } [HttpGet] [ProducesResponseType(typeof(PagedResponse), 200)] public async Task>> GetAll( [FromQuery] ProposalFilterRequest filter, CancellationToken ct) { var result = await _proposalService.GetAllAsync(filter, ct); return Ok(result); } [HttpGet("{id:guid}")] [ProducesResponseType(typeof(ProposalResponse), 200)] [ProducesResponseType(404)] public async Task> GetById(Guid id, CancellationToken ct) { var result = await _proposalService.GetByIdAsync(id, ct); if (result == null) return NotFound(); return Ok(result); } [HttpPut("{id:guid}")] [Authorize(Roles = "admins,sysadmins")] [ProducesResponseType(typeof(ProposalResponse), 200)] [ProducesResponseType(400)] [ProducesResponseType(404)] public async Task> Update( Guid id, [FromBody] UpdateProposalRequest request, CancellationToken ct) { var result = await _proposalService.UpdateAsync(id, request, ct); return Ok(result); } [HttpPost("{id:guid}/approve")] [Authorize(Roles = "admins,sysadmins")] [ProducesResponseType(typeof(ProposalResponse), 200)] [ProducesResponseType(400)] [ProducesResponseType(404)] public async Task> Approve( Guid id, [FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)] ProposalVersionRequest? request, CancellationToken ct) { var result = await _proposalService.ApproveAsync(id, request?.ProposalVersion, ct); return Ok(result); } [HttpPost("{id:guid}/return-to-review")] [Authorize(Roles = "admins,sysadmins")] public async Task> ReturnToReview( Guid id, [FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)] ProposalVersionRequest? request, CancellationToken ct) { var result = await _proposalService.ReturnToReviewAsync(id, request?.ProposalVersion, ct); return Ok(result); } [HttpPost("{id:guid}/send")] [Authorize(Roles = "admins,sysadmins")] public async Task> MarkSent( Guid id, [FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)] ProposalVersionRequest? request, CancellationToken ct) { var result = await _proposalService.MarkSentAsync(id, request?.ProposalVersion, ct); return Ok(result); } [HttpPost("{id:guid}/revise")] [Authorize(Roles = "admins,sysadmins")] public async Task> Revise( Guid id, [FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)] ProposalVersionRequest? request, CancellationToken ct) { var result = await _proposalService.ReviseAsync(id, request?.ProposalVersion, ct); return Ok(result); } [HttpGet("{id:guid}/history")] public async Task>> GetHistory(Guid id, CancellationToken ct) { var result = await _proposalService.GetRevisionHistoryAsync(id, ct); return Ok(result); } [HttpGet("{id:guid}/audit")] [Authorize(Roles = "admins,sysadmins")] public async Task>> GetAudit(Guid id, CancellationToken ct) { var result = await _proposalService.GetAuditTrailAsync(id, ct); return Ok(result); } [HttpGet("{id:guid}/similar")] [Authorize(Roles = "admins,sysadmins")] public async Task>> GetSimilar(Guid id, CancellationToken ct) { var result = await _similarService.GetSimilarProposalsAsync(id, ct); return Ok(result); } [HttpPost("{id:guid}/generate-suggestions")] [Authorize(Roles = "admins,sysadmins")] public async Task GenerateSuggestions(Guid id, CancellationToken ct) { await _jobPublisher.PublishAsync("suggestions", new { proposalId = id, trigger = "generate" }, ct); return Accepted(); } [HttpPost("{id:guid}/regenerate")] [Authorize(Roles = "admins,sysadmins")] public async Task Regenerate(Guid id, CancellationToken ct) { await _jobPublisher.PublishAsync("suggestions", new { proposalId = id, trigger = "regenerate" }, ct); return Accepted(); } [HttpGet("stats")] public async Task> GetStats(CancellationToken ct) { var stats = await _proposalService.GetStatsAsync(ct); return Ok(stats); } [HttpPost("{id:guid}/similar-references")] [Authorize(Roles = "admins,sysadmins")] public async Task AddSimilarReference( Guid id, [FromBody] CreateSimilarReferenceRequest request, CancellationToken ct) { await _similarService.AddReferenceAsync(id, request, ct); return Created(); } }