using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using eprintServer.Entities; using eprintServer.Requests; using eprintServer.Services; using eprintServer.Interfaces; using eprintServer.Responses; using System; using eprintServer.Data; using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; // Ensure this is present for IFormFile namespace eprintServer.Controllers { // Base URL: /api/offers [Route("api/[controller]")] [ApiController] [Authorize(Roles = "ADMIN,SUB_ADMIN")] public class OffersController : ControllerBase { private readonly OfferService _offerService; private readonly IFileStorageService _fileStorageService; private readonly DataContext _context; // Constructor with Dependency Injection public OffersController(DataContext context,IFileStorageService fileStorageService, OfferService offerService) { _offerService = offerService; _fileStorageService = fileStorageService; _context = context; } [HttpGet] public async Task>> GetAll() { var offers = await _offerService.GetAllOffersAsync(); return Ok(offers); } [HttpGet("get-with-filters")] public async Task>> GetAll( [FromQuery] bool? active, [FromQuery] bool? isFeatured, [FromQuery] bool? isPublic) { var offers = await _offerService.GetAllOffersAsync(active, isFeatured, isPublic); return Ok(offers); } [HttpGet("{id}")] public async Task> GetById(int id) { var offer = await _offerService.GetOfferByIdAsync(id); if (offer == null) { return NotFound(); } return Ok(offer); } [HttpPost] public async Task> Create([FromBody] CreateOfferRequest request) { if (!ModelState.IsValid) { return BadRequest(ModelState); } try { var createdOffer = await _offerService.CreateOfferAsync(request); return CreatedAtAction(nameof(GetById), new { id = createdOffer.Id }, createdOffer); } catch (Exception ex) { return StatusCode(500, $"Internal server error: {ex.Message}"); } } // FIX: Changed return type from IActionResult to ActionResult // and returns the updated object. [HttpPut("{id}")] public async Task> Update(int id, [FromBody] UpdateOfferRequest request) { if (!ModelState.IsValid) { return BadRequest(ModelState); } try { var updatedOffer = await _offerService.UpdateOfferAsync(id, request); return Ok(updatedOffer); // Return the fully loaded updated object (200 OK) } catch (KeyNotFoundException) { return NotFound(); } catch (Exception ex) { return StatusCode(500, $"Internal server error: {ex.Message}"); } } [HttpDelete("{id}")] public async Task Delete(int id) { try { await _offerService.DeleteOfferAsync(id); return NoContent(); // 204 Success } catch (KeyNotFoundException) { return NotFound(); } catch (Exception ex) { return StatusCode(500, $"Internal server error: {ex.Message}"); } } [HttpPatch("{id}/status")] public async Task ChangeStatus(int id, [FromBody] StatusChangeRequest request) { if (string.IsNullOrEmpty(request.Status)) { return BadRequest("Status field is required."); } try { await _offerService.ChangeOfferStatusAsync(id, request.Status); return NoContent(); // 204 Success } catch (KeyNotFoundException) { return NotFound(); } catch (Exception ex) { return StatusCode(500, $"Internal server error: {ex.Message}"); } } [HttpPost("upload-banner-image/{offerId:int}")] public async Task> UploadOfferBannerImage(int offerId, IFormFile image) { if (image == null || image.Length == 0) { return BadRequest("An image file is required."); } // 1. Find the target Offer var offer = await _context.Offers .FirstOrDefaultAsync(o => o.Id == offerId); if (offer == null) { return NotFound($"Offer with ID {offerId} not found."); } FileModel? fileModel = null; try { const string SubDirectory = "offers"; fileModel = await _fileStorageService.SaveFileAsync(image, SubDirectory); if (offer.BannerImageId.HasValue) { await _fileStorageService.DeleteFileAsync(offer.BannerImageId.Value); } offer.BannerImageId = fileModel.Id; offer.UpdatedAt = DateTime.UtcNow; await _context.SaveChangesAsync(); var response = new ProductImageUploadResponse(fileModel); return Ok(response); } catch (Exception ex) { if (fileModel != null) { try { await _fileStorageService.DeleteFileAsync(fileModel.Id); } catch { } } return StatusCode(500, $"Something went wrong during offer banner image upload: {ex.Message}"); } } [HttpPost("upload-product-image/{offerProductId:int}")] public async Task> UploadOfferProductImage(int offerProductId, IFormFile image) { if (image == null || image.Length == 0) { return BadRequest("An image file is required."); } var offerProduct = await _context.OfferProducts .FirstOrDefaultAsync(op => op.Id == offerProductId); if (offerProduct == null) { return NotFound($"Offer Product with ID {offerProductId} not found."); } FileModel? fileModel = null; try { const string SubDirectory = "offerProducts"; fileModel = await _fileStorageService.SaveFileAsync(image, SubDirectory); if (offerProduct.ProductImageId.HasValue) { await _fileStorageService.DeleteFileAsync(offerProduct.ProductImageId.Value); } offerProduct.ProductImageId = fileModel.Id; await _context.SaveChangesAsync(); var response = new ProductImageUploadResponse(fileModel); return Ok(response); } catch (Exception ex) { if (fileModel != null) { try { await _fileStorageService.DeleteFileAsync(fileModel.Id); } catch { } } return StatusCode(500, $"Something went wrong during offer product image upload: {ex.Message}"); } } } }