using DocumentOperator.Application.Common.DTOs;
using DocumentOperator.Application.Features.Documents.ExtractSwissQrCode;
using DocumentOperator.Application.Features.Documents.ValidatePdf;
using DocumentOperator.Domain.Models.ValueObjects;
using MediatR;
using Microsoft.AspNetCore.Mvc;
namespace DocumentOperator.API.Endpoints.v1;
///
/// Document endpoints (Minimal API)
///
public static class DocumentEndpoints
{
///
/// Maps all document-related endpoints
///
public static void MapDocumentEndpoints(this IEndpointRouteBuilder app)
{
var group = app.MapGroup("/api/v1/documents")
.WithTags("Documents");
// POST /api/v1/documents/validate
group.MapPost("/validate", ValidatePdf)
.WithName("ValidatePdf")
.WithSummary("Validates a PDF document and returns metadata")
.WithDescription("Validates the PDF format and extracts metadata (page count, file size, PDF version, attachments)")
.Produces(StatusCodes.Status200OK)
.Produces(StatusCodes.Status400BadRequest)
.Produces(StatusCodes.Status500InternalServerError);
// POST /api/v1/documents/extract-swiss-qr-code
group.MapPost("/extract-swiss-qr-code", ExtractSwissQrCode)
.WithName("ExtractSwissQrCode")
.WithSummary("Extracts Swiss QR Code from the last page of a PDF document")
.WithDescription("Extracts and parses a Swiss QR Code (Swiss QR Bill Standard 2.0) from the last page of a PDF. Returns references (passed through) and all QR code fields.")
.Produces(StatusCodes.Status200OK)
.Produces(StatusCodes.Status400BadRequest)
.Produces(StatusCodes.Status404NotFound)
.Produces(StatusCodes.Status500InternalServerError);
}
///
/// Validates a PDF document and returns metadata
///
/// PDF as Base64 string
/// MediatR instance
/// Cancellation token
/// PDF metadata (page count, file size, etc.)
/// PDF is valid, metadata returned
/// Invalid PDF or Base64 format
/// Internal server error during validation
private static async Task ValidatePdf(
ValidatePdfRequest request,
IMediator mediator,
CancellationToken cancellationToken)
{
// DTO → Query (Value Objects erstellen - kann DomainValidationException werfen!)
var query = new ValidatePdfQuery(
Base64String.Create(request.Base64Pdf)
);
// MediatR Handler aufrufen (ValidationBehavior → Handler)
var metadata = await mediator.Send(query, cancellationToken);
// PdfMetadata → Response DTO
var response = new ValidatePdfResponse(
metadata.PageCount,
metadata.FileSizeBytes,
metadata.FileSizeMB,
metadata.PdfVersion,
metadata.HasAttachments,
metadata.AttachmentCount
);
return Results.Ok(response);
}
///
/// Extracts Swiss QR Code from the last page of a PDF document
///
/// References array + PDF as Base64 string
/// MediatR instance
/// Cancellation token
/// References (passed through) + Swiss QR Code data
/// Swiss QR Code extracted successfully
/// Invalid PDF or Base64 format
/// No Swiss QR Code found on the last page
/// Internal server error during extraction
private static async Task ExtractSwissQrCode(
ExtractSwissQrCodeRequest request,
IMediator mediator,
CancellationToken cancellationToken)
{
// DTO → Query (Value Objects erstellen)
var query = new ExtractSwissQrCodeQuery(
References: request.References,
PdfContent: Base64String.Create(request.Base64Pdf)
);
// MediatR Handler aufrufen
var result = await mediator.Send(query, cancellationToken);
// Map Domain Value Object → DTO
var response = new ExtractSwissQrCodeResponse(
References: result.References,
QrCodeData: MapQrCodeDataToDto(result.QrCodeData)
);
return Results.Ok(response);
}
///
/// Maps SwissQrCodeData domain value object to DTO
///
private static SwissQrCodeDataDto MapQrCodeDataToDto(Domain.ValueObjects.SwissQrCodeData qrCodeData)
{
return new SwissQrCodeDataDto(
QrType: qrCodeData.QrType,
Version: qrCodeData.Version,
CodingType: qrCodeData.CodingType,
Iban: qrCodeData.Iban,
Creditor: MapAddressToDto(qrCodeData.Creditor),
UltimateCreditor: qrCodeData.UltimateCreditor != null ? MapAddressToDto(qrCodeData.UltimateCreditor) : null,
Amount: qrCodeData.Amount,
Currency: qrCodeData.Currency,
UltimateDebtor: qrCodeData.UltimateDebtor != null ? MapAddressToDto(qrCodeData.UltimateDebtor) : null,
ReferenceType: qrCodeData.ReferenceType,
Reference: qrCodeData.Reference,
UnstructuredMessage: qrCodeData.UnstructuredMessage,
BillInformation: qrCodeData.BillInformation,
AlternativeProcedureParameters: qrCodeData.AlternativeProcedureParameters
);
}
///
/// Maps AddressData domain value object to DTO
///
private static AddressDataDto MapAddressToDto(Domain.ValueObjects.AddressData address)
{
return new AddressDataDto(
AddressType: address.AddressType,
Name: address.Name,
Street: address.Street,
BuildingNumber: address.BuildingNumber,
AddressLine1: address.AddressLine1,
AddressLine2: address.AddressLine2,
PostalCode: address.PostalCode,
City: address.City,
Country: address.Country
);
}
}