// src/Webshop.Api/Controllers/Admin/AdminDiscountsController.cs using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Threading.Tasks; using Webshop.Application; using Webshop.Application.DTOs.Discounts; using Webshop.Application.Services.Admin.Interfaces; namespace Webshop.Api.Controllers.Admin { /// /// API-Endpunkte zur Verwaltung von Rabatten und Gutscheincodes. /// [ApiController] [Route("api/v1/admin/[controller]")] [Authorize(Roles = "Admin")] public class AdminDiscountsController : ControllerBase { private readonly IAdminDiscountService _adminDiscountService; public AdminDiscountsController(IAdminDiscountService adminDiscountService) { _adminDiscountService = adminDiscountService; } /// /// Ruft eine Liste aller konfigurierten Rabatte ab. /// [HttpGet] public async Task>> GetAllDiscounts() { var discounts = await _adminDiscountService.GetAllDiscountsAsync(); return Ok(discounts); } /// /// Ruft einen einzelnen Rabatt anhand seiner eindeutigen ID ab. /// /// Die ID des Rabatts. [HttpGet("{id}")] public async Task> GetDiscountById(Guid id) { var discount = await _adminDiscountService.GetDiscountByIdAsync(id); if (discount == null) return NotFound(); return Ok(discount); } /// /// Erstellt einen neuen Rabatt. /// /// /// **Funktionsweise von Rabatten:** /// - **DiscountType:** 'Percentage' (z.B. 10 für 10%) oder 'FixedAmount' (z.B. 5 für 5,00€). /// - **CouponCode:** Wenn `requiresCouponCode` auf `true` gesetzt ist, muss ein eindeutiger `couponCode` angegeben werden. /// - **Gültigkeit:** Kann durch `startDate` und `endDate` zeitlich begrenzt werden. /// - **Zuweisung:** Der Rabatt kann entweder bestimmten Produkten (`assignedProductIds`) oder ganzen Kategorien (`assignedCategoryIds`) zugewiesen werden. Wenn beide Listen leer sind, gilt der Rabatt für den gesamten Warenkorb (sofern `minimumOrderAmount` erreicht ist). /// /// Das Datenobjekt des zu erstellenden Rabatts. [HttpPost] [ProducesResponseType(typeof(DiscountDto), StatusCodes.Status201Created)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task> CreateDiscount([FromBody] DiscountDto discountDto) { if (!ModelState.IsValid) return BadRequest(ModelState); var result = await _adminDiscountService.CreateDiscountAsync(discountDto); if (result.Type == ServiceResultType.Success) { return CreatedAtAction(nameof(GetDiscountById), new { id = result.Value!.Id }, result.Value); } return BadRequest(new { Message = result.ErrorMessage }); } /// /// Aktualisiert einen bestehenden Rabatt. /// /// Die ID des zu aktualisierenden Rabatts. /// Die neuen Daten für den Rabatt. [HttpPut("{id}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task UpdateDiscount(Guid id, [FromBody] DiscountDto discountDto) { if (id != discountDto.Id) return BadRequest("ID in URL und Body stimmen nicht überein."); if (!ModelState.IsValid) return BadRequest(ModelState); var result = await _adminDiscountService.UpdateDiscountAsync(discountDto); return result.Type switch { ServiceResultType.Success => NoContent(), ServiceResultType.NotFound => NotFound(new { Message = result.ErrorMessage }), ServiceResultType.InvalidInput => BadRequest(new { Message = result.ErrorMessage }), _ => StatusCode(StatusCodes.Status500InternalServerError, "Ein unerwarteter Fehler ist aufgetreten.") }; } /// /// Löscht einen Rabatt. /// /// Die ID des zu löschenden Rabatts. [HttpDelete("{id}")] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task DeleteDiscount(Guid id) { var result = await _adminDiscountService.DeleteDiscountAsync(id); return result.Type switch { ServiceResultType.Success => NoContent(), ServiceResultType.NotFound => NotFound(new { Message = result.ErrorMessage }), _ => StatusCode(StatusCodes.Status500InternalServerError, "Ein unerwarteter Fehler ist aufgetreten.") }; } } }