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;

/// <summary>
/// Document endpoints (Minimal API)
/// </summary>
public static class DocumentEndpoints
{
    /// <summary>
    /// Maps all document-related endpoints
    /// </summary>
    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<ValidatePdfResponse>(StatusCodes.Status200OK)
            .Produces<ProblemDetails>(StatusCodes.Status400BadRequest)
            .Produces<ProblemDetails>(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 document.

**Requirements:**
- PDF must contain a valid Swiss QR Code on the last page
- QR Code must conform to Swiss QR Bill Standard 2.0
- References array is required (can be empty)

**Returns:**
- All QR code fields (IBAN, amount, creditor, debtor, reference, etc.)
- References array (passed through from request)

**Use Case:**
Extract payment information from Swiss QR invoices for automated processing.")
            .Produces<ExtractSwissQrCodeResponse>(StatusCodes.Status200OK)
            .Produces<ProblemDetails>(StatusCodes.Status400BadRequest)
            .Produces<ProblemDetails>(StatusCodes.Status404NotFound)
            .Produces<ProblemDetails>(StatusCodes.Status500InternalServerError);
    }

    /// <summary>
    /// Validates a PDF document and returns metadata
    /// </summary>
    /// <param name="request">PDF as Base64 string</param>
    /// <param name="mediator">MediatR instance</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>PDF metadata (page count, file size, etc.)</returns>
    /// <response code="200">PDF is valid, metadata returned</response>
    /// <response code="400">Invalid PDF or Base64 format</response>
    /// <response code="500">Internal server error during validation</response>
    private static async Task<IResult> 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);
    }

    /// <summary>
    /// Extracts Swiss QR Code from the last page of a PDF document
    /// </summary>
    /// <param name="request">References array + PDF as Base64 string</param>
    /// <param name="mediator">MediatR instance</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>References (passed through) + Swiss QR Code data</returns>
    /// <response code="200">Swiss QR Code extracted successfully</response>
    /// <response code="400">Invalid PDF or Base64 format</response>
    /// <response code="404">No Swiss QR Code found on the last page</response>
    /// <response code="500">Internal server error during extraction</response>
    private static async Task<IResult> 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);
    }

    /// <summary>
    /// Maps SwissQrCodeData domain value object to DTO
    /// </summary>
    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
        );
    }

    /// <summary>
    /// Maps AddressData domain value object to DTO
    /// </summary>
    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
        );
    }
}
