using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using eprintServer.Services; using eprintServer.Interfaces; using eprintServer.Entities; using eprintServer.Data; using eprintServer.Responses; using eprintServer.Requests; using eprintServer.Requests.CustomizableProduct; using System; using System.Threading.Tasks; namespace eprintServer.Controllers; [ApiController] [Route("api/admin/[controller]")] [Authorize(Roles = "ADMIN,SUB_ADMIN")] public class CustomizableProductController : ControllerBase { private readonly CustomizableProductService _service; private readonly IFileStorageService _fileStorageService; private readonly DataContext _context; public CustomizableProductController(CustomizableProductService service, IFileStorageService fileStorageService, DataContext context) { _service = service; _fileStorageService = fileStorageService; _context = context; } [HttpPost] public async Task Create([FromBody] CreateCustomizableProductRequest request) { try { var product = await _service.CreateProductAsync(request); return Ok(product); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } [HttpPut("{id}")] public async Task Update(long id, [FromBody] UpdateCustomizableProductRequest request) { try { var product = await _service.UpdateProductAsync(id, request); return Ok(product); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } [HttpGet("{id}")] [AllowAnonymous] public async Task GetById(long id) { try { var product = await _service.GetProductByIdAsync(id); return Ok(product); } catch (Exception ex) { return NotFound(new { message = ex.Message }); } } [HttpGet("get-all-product-details-by-id/{id}")] [AllowAnonymous] public async Task GetWithDetailsById(long id) { try { var product = await _service.GetProductDetailByIdAsync(id); return Ok(product); } catch (Exception ex) { return NotFound(new { message = ex.Message }); } } [HttpGet] [AllowAnonymous] public async Task GetAll([FromQuery] bool includeArchived = false) { var products = await _service.GetAllProductsAsync(includeArchived); return Ok(products); } [HttpGet("category/{categoryId}")] [AllowAnonymous] public async Task GetByCategory(long categoryId) { var products = await _service.GetProductsByCategoryAsync(categoryId); return Ok(products); } [HttpDelete("{id}")] public async Task Delete(long id) { var result = await _service.DeleteProductAsync(id); if (!result) return NotFound(new { message = "Product not found" }); return Ok(new { message = "Product deleted successfully" }); } [HttpPost("upload-image/{productId:long}")] public async Task> UploadProductImage(long productId, IFormFile image) { if (image == null || image.Length == 0) { return BadRequest("An image file is required."); } try { const string SubDirectory = "customizableProductImages"; var fileModel = await _fileStorageService.SaveFileAsync(image, SubDirectory); var updatedProduct = await _service.UpdateProductImageAsync(productId, fileModel); if (updatedProduct == null) { await _fileStorageService.DeleteFileAsync(fileModel.Id); return NotFound($"Customizable Product with ID {productId} not found. Image upload failed."); } var response = new ProductImageUploadResponse(fileModel); return Ok(response); } catch (Exception ex) { return StatusCode(500, $"Something went wrong during customizable product image upload: {ex.Message}"); } } [HttpPost("{productId}/add-mockup")] public async Task AddMockup( long productId, IFormFile file, IFormFile thumbnail, [FromQuery] string name, [FromQuery] double designWidth, [FromQuery] double designHeight, [FromQuery] double printWidth, [FromQuery] double printHeight) { if (file == null) return BadRequest("Mockup file is required"); try { const string SubDirectory = "productMockups"; var fileModel = await _fileStorageService.SaveFileAsync(file, SubDirectory); FileModel? thumbFileModel = null; if (thumbnail != null) { thumbFileModel = await _fileStorageService.SaveFileAsync(thumbnail, SubDirectory); } var mockup = await _service.AddMockupToProductAsync(productId, fileModel, thumbFileModel, name, designWidth, designHeight, printWidth, printHeight); return Ok(mockup); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } [HttpPut("update-mockup/{mockupId}")] public async Task UpdateMockup( long mockupId, IFormFile? file, IFormFile thumbnail, [FromQuery] string? name, [FromQuery] double? designWidth, [FromQuery] double? designHeight, [FromQuery] double? printWidth, [FromQuery] double? printHeight) { try { FileModel? fileModel = null; if (file != null) { const string SubDirectory = "productMockups"; fileModel = await _fileStorageService.SaveFileAsync(file, SubDirectory); } FileModel? thumbFileModel = null; if (thumbnail != null) { const string SubDirectory = "productMockups"; thumbFileModel = await _fileStorageService.SaveFileAsync(thumbnail, SubDirectory); } var updatedMockup = await _service.UpdateMockupAsync(mockupId, fileModel, thumbFileModel, name, designWidth, designHeight, printWidth, printHeight); if (updatedMockup == null) return NotFound("Mockup not found"); return Ok(updatedMockup); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } [HttpDelete("delete-mockup/{mockupId}")] public async Task DeleteMockup(long mockupId) { try { var result = await _service.DeleteMockupAsync(mockupId); if (!result) return NotFound("Mockup not found"); return Ok(new { message = "Mockup and associated file deleted successfully" }); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } [HttpPatch("{productId}/3d-config")] public async Task Patch3DConfig(long productId, [FromBody] Patch3DRequest request) { try { var product = await _service.Patch3DConfiguration(productId, request); if (product == null) return NotFound(new { message = "Product not found" }); return Ok(product); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } [HttpGet("{productId}/3d-data")] [AllowAnonymous] public async Task Get3DData(long productId) { try { var data = await _service.GetProduct3DData(productId); if (data == null) return NotFound(new { message = "Product not found" }); return Ok(data); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } [HttpPut("update-texture-slot-file/{textureSlotId}")] public async Task UpdateTextureSlotFile(long textureSlotId, IFormFile? file) { try { FileModel? fileModel = null; if (file != null) { // Convert IFormFile to FileModel by saving to storage const string SubDirectory = "textureSlotFiles"; fileModel = await _fileStorageService.SaveFileAsync(file, SubDirectory); } var updatedSlot = await _service.UpdateTextureSlotFileAsync(textureSlotId, fileModel); return Ok(updatedSlot); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } [HttpPut("{productId}/update-3d-files")] public async Task Update3DFiles( long productId, IFormFile? uvMapImage, IFormFile? threeDModelFile) { try { FileModel? uvMapModel = null; FileModel? threeDModel = null; // Process UV Map if provided if (uvMapImage != null) { uvMapModel = await _fileStorageService.SaveFileAsync(uvMapImage, "uvMaps"); } // Process 3D File if provided if (threeDModelFile != null) { threeDModel = await _fileStorageService.SaveFileAsync(threeDModelFile, "3dModels"); } // Pass the generated FileModel objects to the service var updatedProduct = await _service.Update3DFilesAsync(productId, uvMapModel, threeDModel); return Ok(updatedProduct); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } [HttpPost("/branching-scenario/{id}")] public async Task SyncScenario(long id, [FromBody] SyncBranchingScenarioRequest request) { try { var result = await _service.SyncBranchingScenarioAsync(id, request); if (!result) return NotFound("Product not found"); return Ok(new { message = "Branching scenario updated and enabled successfully." }); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } [HttpDelete("disable-branching/{id}")] public async Task DisableBranching(long id) { try { var result = await _service.DisableBranchingAsync(id); if (!result) return NotFound("Product not found"); return Ok(new { message = "Branching disabled and reset to normal order." }); } catch (Exception ex) { return BadRequest(new { message = ex.Message }); } } }