using System.Net.Mime;
using Microsoft.AspNetCore.Mvc;
using SchotzIadKmTracker.Api.Services;
using SchotzIadKmTracker.Api.Services.Exceptions;
namespace SchotzIadKmTracker.Api.Controllers;
///
/// Endpoints d'Export_PDF : rapport mensuel et synthèse annuelle (Exigences 7.3, 7.4, 7.5).
/// Chaque réponse renvoie un unique fichier application/pdf avec l'en-tête
/// Content-Disposition: attachment et le nom de fichier suggéré par le service
/// (trajets_MM_AAAA.pdf pour le mensuel, trajets_AAAA.pdf pour l'annuel).
///
/// Le filtre par véhicule est optionnel : si vehiculeId est omis, le Véhicule_Courant
/// est utilisé par défaut.
///
///
/// Note (Exigence 7.9) : une réponse HTTP unique ne peut transporter qu'un seul fichier.
/// Ces endpoints produisent donc le rapport du véhicule sélectionné (ou courant). La génération
/// d'un rapport distinct par véhicule lorsqu'une période comporte plusieurs véhicules est assurée
/// par les variantes de service GenererRapports…ParVehiculeAsync, réservées à un usage
/// multi-fichiers ultérieur (p. ex. archive). Ici, un appel = un fichier filtré par véhicule.
///
///
///
/// Erreurs : un dépassement du délai de génération ou un échec de rendu lève une
/// mappée vers 503 Service Unavailable ; un véhicule
/// introuvable lève une mappée vers 404 Not Found
/// (réponses ProblemDetails).
///
///
[ApiController]
[Route("api/exports")]
public class ExportsPdfController : ControllerBase
{
private readonly IPdfService _pdfService;
private readonly IVehiculeService _vehiculeService;
public ExportsPdfController(IPdfService pdfService, IVehiculeService vehiculeService)
{
_pdfService = pdfService;
_vehiculeService = vehiculeService;
}
///
/// Génère et télécharge le rapport PDF mensuel d'un (année, mois) pour le véhicule indiqué
/// (Véhicule_Courant si est omis). Retourne les octets du PDF
/// avec Content-Type: application/pdf et Content-Disposition: attachment;
/// filename="trajets_MM_AAAA.pdf" (Exigences 7.3, 7.4).
///
[HttpGet("mensuel/{annee:int}/{mois:int}")]
[Produces(MediaTypeNames.Application.Pdf)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
public async Task ExporterMensuel(
int annee, int mois, [FromQuery] int? vehiculeId, CancellationToken cancellationToken)
{
try
{
var vehicule = await ResoudreVehiculeIdAsync(vehiculeId, cancellationToken);
var pdf = await _pdfService.GenererRapportMensuelAsync(annee, mois, vehicule, cancellationToken);
return FichierPdf(pdf);
}
catch (VehiculeNotFoundException ex)
{
return Problem(detail: ex.Message, statusCode: StatusCodes.Status404NotFound);
}
catch (PdfGenerationException ex)
{
return Problem(detail: ex.Message, statusCode: StatusCodes.Status503ServiceUnavailable);
}
}
///
/// Génère et télécharge la synthèse PDF annuelle d'une année pour le véhicule indiqué
/// (Véhicule_Courant si est omis). Retourne les octets du PDF
/// avec Content-Type: application/pdf et Content-Disposition: attachment;
/// filename="trajets_AAAA.pdf" (Exigences 7.3, 7.4).
///
[HttpGet("annuel/{annee:int}")]
[Produces(MediaTypeNames.Application.Pdf)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
public async Task ExporterAnnuel(
int annee, [FromQuery] int? vehiculeId, CancellationToken cancellationToken)
{
try
{
var vehicule = await ResoudreVehiculeIdAsync(vehiculeId, cancellationToken);
var pdf = await _pdfService.GenererRapportAnnuelAsync(annee, vehicule, cancellationToken);
return FichierPdf(pdf);
}
catch (VehiculeNotFoundException ex)
{
return Problem(detail: ex.Message, statusCode: StatusCodes.Status404NotFound);
}
catch (PdfGenerationException ex)
{
return Problem(detail: ex.Message, statusCode: StatusCodes.Status503ServiceUnavailable);
}
}
///
/// Résout l'identifiant du véhicule à utiliser : celui fourni s'il est présent, sinon
/// le Véhicule_Courant (Date_Effet la plus récente <= aujourd'hui).
///
private async Task ResoudreVehiculeIdAsync(int? vehiculeId, CancellationToken cancellationToken)
{
if (vehiculeId.HasValue)
{
return vehiculeId.Value;
}
var courant = await _vehiculeService.GetVehiculeCourantAsync(cancellationToken);
return courant.Id;
}
///
/// Renvoie le PDF en pièce jointe téléchargeable, en s'appuyant sur le nom de fichier
/// suggéré par le (Content-Disposition: attachment).
///
private FileContentResult FichierPdf(PdfResult pdf)
=> File(pdf.Contenu, MediaTypeNames.Application.Pdf, pdf.NomFichier);
}