using CashLineERP.Application.Health;
using CashLineERP.Application.Documents;
using CashLineERP.Application.Customers;
using CashLineERP.Application.Finance;
using CashLineERP.Application.Identity;
using CashLineERP.Application.IslamicFinance.ContractTemplates;
using CashLineERP.Application.IslamicFinance.Disbursements;
using CashLineERP.Application.IslamicFinance.Facilities;
using CashLineERP.Application.IslamicFinance.Murabaha;
using CashLineERP.Application.IslamicFinance.PartnerLenders;
using CashLineERP.Application.IslamicFinance.ProductProfiles;
using CashLineERP.Application.IslamicFinance.ReceivablesFinance;
using CashLineERP.Application.IslamicFinance.Requests;
using CashLineERP.Application.IslamicFinance.Settlements;
using CashLineERP.Application.IslamicFinance.Shariah;
using CashLineERP.Application.Internal;
using CashLineERP.Application.Integration;
using CashLineERP.Application.External;
using CashLineERP.Application.Inventory;
using CashLineERP.Application.Localization;
using CashLineERP.Application.MasterData;
using CashLineERP.Application.Notifications;
using CashLineERP.Application.Parties;
using CashLineERP.Application.Pricing;
using CashLineERP.Application.Privacy;
using CashLineERP.Application.Procurement;
using CashLineERP.Application.Reporting;
using CashLineERP.Application.Sales;
using CashLineERP.Application.Suppliers;
using CashLineERP.Application.Tax;
using CashLineERP.Application.Workflow;
using CashLineERP.Api.Infrastructure;
using CashLineERP.Contracts.Parties;
using CashLineERP.Contracts.Customers;
using CashLineERP.Contracts.Documents;
using CashLineERP.Contracts.Finance;
using CashLineERP.Contracts.External;
using CashLineERP.Contracts.Integration;
using CashLineERP.Contracts.Internal;
using CashLineERP.Contracts.Inventory;
using CashLineERP.Contracts.Identity;
using CashLineERP.Contracts.IslamicFinance;
using CashLineERP.Contracts.Localization;
using CashLineERP.Contracts.MasterData;
using CashLineERP.Contracts.Notifications;
using CashLineERP.Contracts.Pricing;
using CashLineERP.Contracts.Privacy;
using CashLineERP.Contracts.Procurement;
using CashLineERP.Contracts.Reporting;
using CashLineERP.Contracts.Sales;
using CashLineERP.Contracts.Suppliers;
using CashLineERP.Contracts.Tax;
using CashLineERP.Infrastructure.DependencyInjection;
using CashLineERP.SharedKernel.Identity;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using System.IO;
using System.Security.Claims;
using System.Text.Json;

LogStartup("Creating WebApplicationBuilder.");
var builder = WebApplication.CreateSlimBuilder(args);
LogStartup("WebApplicationBuilder created.");
var apiJsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web);

LogStartup("Registering infrastructure services.");
builder.Services.AddCashLineInfrastructure(builder.Configuration, builder.Environment.ContentRootPath);
LogStartup("Infrastructure services registered.");
builder.Services.AddSingleton<IAccessTokenService, SimpleAccessTokenService>();
builder.Services.AddSingleton<ReleaseGovernanceMetadataProvider>();
builder.Services.AddAuthentication("Bearer")
    .AddScheme<AuthenticationSchemeOptions, BearerAccessTokenAuthenticationHandler>("Bearer", _ => { });
builder.Services.AddAuthorization();
LogStartup("Authentication and authorization services registered.");

LogStartup("Building web application.");
var app = builder.Build();
LogStartup($"Web application built. Environment={app.Environment.EnvironmentName}.");
var webRootPath = app.Environment.WebRootPath ?? Path.Combine(app.Environment.ContentRootPath, "wwwroot");
var cutoverRootPath = Path.Combine(webRootPath, "cutover");
var uatLiveRootPath = Path.Combine(webRootPath, "uat-live");
var uatV3RootPath = Path.Combine(webRootPath, "uat-v3");

if (app.Environment.IsEnvironment("Testing"))
{
    app.Use(async (context, next) =>
    {
        var responseBodyFeature = context.Features.Get<IHttpResponseBodyFeature>();
        if (responseBodyFeature is not null && responseBodyFeature is not CompatibleHttpResponseBodyFeature)
        {
            context.Features.Set<IHttpResponseBodyFeature>(new CompatibleHttpResponseBodyFeature(responseBodyFeature));
        }

        await next();
    });
}

app.Use(async (context, next) =>
{
    try
    {
        await next();
    }
    catch (InvalidOperationException exception)
    {
        context.Response.StatusCode = StatusCodes.Status400BadRequest;
        context.Response.ContentType = "application/json";
        var payload = JsonSerializer.Serialize(new
        {
            error = "invalid_operation",
            message = exception.Message,
            detail = app.Environment.IsEnvironment("Testing") ? exception.ToString() : null
        }, apiJsonOptions);
        await context.Response.WriteAsync(payload);
    }
});

MapLegacyWorkspaceRedirect("/cutover", "/uat-v3");
MapLegacyWorkspaceRedirect("/uat-live", "/uat-v3");
MapFrontendWorkspaceHost("/uat-v3", uatV3RootPath, requireAuthCookieForProtectedRoutes: true);

void MapLegacyWorkspaceRedirect(string mountPath, string targetMountPath)
{
    app.Map(mountPath, redirectApp =>
    {
        redirectApp.Run(context =>
        {
            var requestPath = context.Request.Path.Value ?? "/";
            var query = context.Request.QueryString.HasValue ? context.Request.QueryString.Value : string.Empty;
            var normalizedPath = string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
                || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase)
                ? "/login"
                : requestPath;
            context.Response.Redirect($"{targetMountPath}{normalizedPath}{query}", permanent: false);
            return Task.CompletedTask;
        });
    });
}

void MapFrontendWorkspaceHost(string mountPath, string rootPath, bool requireAuthCookieForProtectedRoutes)
{
    if (!Directory.Exists(rootPath))
    {
        return;
    }

    var cutoverFileProvider = new PhysicalFileProvider(rootPath);
    var cutoverProtectedRoutes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
    {
        "/supplier",
        "/customer",
        "/islamic-finance",
        "/finance-approvals",
        "/operations-control",
        "/reporting-center",
        "/workflow-monitoring"
    };
    const string cutoverAuthCookieName = "cashline-kendo-auth";
    app.Map(mountPath, cutoverApp =>
    {
        cutoverApp.Use(async (context, next) =>
        {
            var requestPath = context.Request.Path.Value ?? "/";
            if (string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase)
                && !context.Request.Cookies.ContainsKey(cutoverAuthCookieName))
            {
                context.Response.Redirect($"{mountPath}/login", permanent: false);
                return;
            }

            await next();
        });
        cutoverApp.UseDefaultFiles(new DefaultFilesOptions
        {
            FileProvider = cutoverFileProvider
        });
        cutoverApp.UseStaticFiles(new StaticFileOptions
        {
            FileProvider = cutoverFileProvider,
            OnPrepareResponse = context =>
            {
                var extension = Path.GetExtension(context.File.Name);
                // In local UAT we rebuild the Angular shell frequently. If JS/CSS are cached, the browser can hold an
                // old "main-*.js" which references chunks that no longer exist after a rebuild, breaking navigation.
                // Disable caching for the SPA shell assets to keep the portal + desktop app consistently up to date.
                if (string.Equals(extension, ".html", StringComparison.OrdinalIgnoreCase)
                    || string.Equals(extension, ".js", StringComparison.OrdinalIgnoreCase)
                    || string.Equals(extension, ".css", StringComparison.OrdinalIgnoreCase)
                    || string.Equals(extension, ".json", StringComparison.OrdinalIgnoreCase)
                    || string.Equals(extension, ".map", StringComparison.OrdinalIgnoreCase))
                {
                    context.Context.Response.Headers.CacheControl = "no-store, no-cache, must-revalidate";
                    context.Context.Response.Headers.Pragma = "no-cache";
                    context.Context.Response.Headers.Expires = "0";
                }
            }
        });
        cutoverApp.Run(async context =>
        {
            if (Path.HasExtension(context.Request.Path.Value))
            {
                context.Response.StatusCode = StatusCodes.Status404NotFound;
                return;
            }

            var requestPath = context.Request.Path.Value ?? "/";
            if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase))
            {
                context.Response.Redirect($"{mountPath}/login", permanent: false);
                return;
            }

            if (cutoverProtectedRoutes.Contains(requestPath)
                && (!requireAuthCookieForProtectedRoutes || !context.Request.Cookies.ContainsKey(cutoverAuthCookieName)))
            {
                var encodedReturnUrl = Uri.EscapeDataString(requestPath);
                context.Response.Redirect($"{mountPath}/login?returnUrl={encodedReturnUrl}", permanent: false);
                return;
            }

            context.Response.ContentType = "text/html; charset=utf-8";
            context.Response.Headers.CacheControl = "no-store, no-cache, must-revalidate";
            context.Response.Headers.Pragma = "no-cache";
            context.Response.Headers.Expires = "0";
            await context.Response.SendFileAsync(Path.Combine(rootPath, "index.html"));
        });
    });
}

app.Use(async (context, next) =>
{
    var requestPath = context.Request.Path.Value ?? "/";
    if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/login", StringComparison.OrdinalIgnoreCase))
    {
        context.Response.Redirect("/uat-v3/login", permanent: false);
        return;
    }

    await next();
});

app.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthentication();
app.UseAuthorization();
LogStartup("Default files, static files, authentication, and authorization middleware configured.");

app.Use(async (context, next) =>
{
    if (!context.Request.Path.StartsWithSegments("/api/v1")
        || context.Request.Path.StartsWithSegments("/api/v1/auth/login")
        || context.Request.Path.StartsWithSegments("/api/v1/auth/me")
        || context.Request.Path.StartsWithSegments("/api/v1/public/onboarding")
        || context.Request.Path.StartsWithSegments("/api/v1/public/privacy")
        || context.Request.Path.StartsWithSegments("/api/v1/build-info")
        || context.Request.Path.StartsWithSegments("/api/v1/demo/bootstrap")
        || context.Request.Path.StartsWithSegments("/api/v1/integrations/eta/ping")
        || context.Request.Path.StartsWithSegments("/api/v1/integrations/eta/notifications/documents")
        || context.Request.Path.StartsWithSegments("/api/v1/payments/channels"))
    {
        await next();
        return;
    }

    if (!(context.User.Identity?.IsAuthenticated ?? false))
    {
        await context.ChallengeAsync("Bearer");
        return;
    }

    if (TryGetExternalPartyId(context.Request.Path, out var externalPartyId))
    {
        if (!string.Equals(context.User.FindFirstValue(ApiClaimTypes.UserType), UserTypeCode.External, StringComparison.OrdinalIgnoreCase)
            || !long.TryParse(context.User.FindFirstValue(ApiClaimTypes.PartyId), out var authenticatedPartyId)
            || authenticatedPartyId != externalPartyId)
        {
            context.Response.StatusCode = StatusCodes.Status403Forbidden;
            await context.Response.WriteAsJsonAsync(new
            {
                error = "forbidden",
                message = "Authenticated external user cannot access the requested party context."
            });
            return;
        }
    }
    else if (!string.Equals(context.User.FindFirstValue(ApiClaimTypes.UserType), UserTypeCode.Internal, StringComparison.OrdinalIgnoreCase))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "This API route requires an internal authenticated user."
        });
        return;
    }

    if (RequiresIamAdminRole(context.Request.Path)
        && !HasAnyRole(context.User, "SUPER_ADMIN", "SYSTEM_OWNER"))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "User administration requires a Super Admin user."
        });
        return;
    }

    if (IsSuperAdminOnlyIdentity(context.User)
        && !IsIamAdministrationPath(context.Request.Path))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "The administrator account is restricted to user administration functions."
        });
        return;
    }

    if (IsSystemOwnerOnlyIdentity(context.User)
        && !IsIamAdministrationPath(context.Request.Path))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "The System Owner account is restricted to Administrator bootstrap and governance functions."
        });
        return;
    }

    if (IsAccountingOfficeIdentity(context.User)
        && context.Request.Path.StartsWithSegments("/api/v1/internal", out var internalRemainder)
        && !internalRemainder.StartsWithSegments("/onboarding", StringComparison.OrdinalIgnoreCase))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "Accounting Office users cannot access internal workbench APIs outside the onboarding scope."
        });
        return;
    }

    if (TryResolveRequiredFunctionCodes(context.Request.Path, out var requiredFunctionCodes)
        && !HasAnyFunction(context.User, requiredFunctionCodes))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "This function is not assigned to the authenticated user."
        });
        return;
    }

    if (TryResolveRequiredFunctionCodes(context.Request.Path, out requiredFunctionCodes)
        && !context.RequestServices.GetRequiredService<IAdminUserService>().AnyFunctionEnabled(requiredFunctionCodes))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "This function is currently disabled by Administrator function governance."
        });
        return;
    }

    if (RequiresEtaNotificationOperationsRole(context.Request.Path)
        && !HasAnyRole(
            context.User,
            "SUPER_ADMIN",
            "ADMIN",
            "FINANCE_MAKER",
            "FINANCE_CHECKER",
            "ERP_OPS_MAKER",
            "ERP_PROCUREMENT_MAKER",
            "ERP_INVENTORY_CONTROLLER",
            "ERP_SALES_OPERATOR"))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "ETA notification operations require a finance or support-authorized internal user."
        });
        return;
    }

    if (RequiresFinanceRole(context.Request.Path)
        && !HasAnyRole(
            context.User,
            "FINANCE_MAKER",
            "FINANCE_CHECKER"))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "This finance API route requires a finance-authorized internal user."
        });
        return;
    }

    if (RequiresCounterpartyGovernanceRole(context.Request.Path)
        && !HasAnyRole(
            context.User,
            "SUPER_ADMIN",
            "ADMIN",
            "ERP_OPS_MAKER",
            "ERP_PROCUREMENT_MAKER",
            "ERP_SALES_OPERATOR",
            "FINANCE_CHECKER",
            "SUPPLIER_ADMIN",
            "CUSTOMER_ADMIN"))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "This supplier/customer governance API route requires a counterparty-authorized internal user."
        });
        return;
    }

    if (RequiresIslamicFinanceOfficerRole(context.Request.Path)
        && !HasAnyRole(
            context.User,
            "SUPER_ADMIN",
            "ADMIN",
            "IF_OPERATIONS_MAKER",
            "FINANCE_CHECKER"))
    {
        context.Response.StatusCode = StatusCodes.Status403Forbidden;
        await context.Response.WriteAsJsonAsync(new
        {
            error = "forbidden",
            message = "This Islamic Finance workbench route requires an Islamic Finance-authorized internal user."
        });
        return;
    }

    await next();
});

LogStartup("Starting Demo UAT bootstrap.");
await DemoUatBootstrapper.InitializeAsync(app.Services, builder.Configuration, app.Environment);
LogStartup("Demo UAT bootstrap completed.");

LogStartup("Beginning route mapping.");
app.MapGet("/health", (IApplicationHealthService healthService, IHostEnvironment environment) =>
{
    var version = typeof(Program).Assembly.GetName().Version?.ToString() ?? "0.0.0";
    var payload = JsonSerializer.Serialize(healthService.GetCurrentStatus(environment.EnvironmentName, version), apiJsonOptions);
    return Results.Text(payload, "application/json");
});

app.MapGet("/api/v1/build-info", (IHostEnvironment environment, ReleaseGovernanceMetadataProvider releaseGovernanceMetadataProvider) =>
{
    var releaseMetadata = releaseGovernanceMetadataProvider.GetCurrent();

    return Results.Ok(new
    {
        service = "CashLineERP.Api",
        environment = environment.EnvironmentName,
        build = typeof(Program).Assembly.GetName().Version?.ToString() ?? "0.0.0",
        apiVersion = releaseMetadata.ApiVersion,
        releaseVersion = releaseMetadata.ReleaseVersion,
        releaseChannel = releaseMetadata.ReleaseChannel,
        supportStatus = releaseMetadata.SupportStatus,
        changelogDoc = releaseMetadata.ChangelogDoc,
        latestReleaseNotesDoc = releaseMetadata.LatestReleaseNotesDoc,
        changePolicyDoc = releaseMetadata.ChangePolicyDoc,
        deprecationPolicyDoc = releaseMetadata.DeprecationPolicyDoc,
        activeDeprecationCount = releaseMetadata.ActiveDeprecationCount
    });
});

app.MapPost("/api/v1/auth/login", (CashLineERP.Contracts.Auth.LoginRequest request, IIdentityService identityService) =>
{
    return Results.Ok(identityService.Login(request));
});

app.MapPost("/api/v1/public/onboarding/leads", (
    CreatePublicOnboardingLeadRequest request,
    IPublicOnboardingService publicOnboardingService) =>
{
    return Results.Ok(publicOnboardingService.CreateLead(request));
});

app.MapGet("/api/v1/public/onboarding/leads/{leadCode}", (
    string leadCode,
    IPublicOnboardingService publicOnboardingService) =>
{
    var lead = publicOnboardingService.GetLead(leadCode);
    return lead is null ? Results.NotFound() : Results.Ok(lead);
});

app.MapPost("/api/v1/public/onboarding/suppliers", (
    CreatePublicSupplierOnboardingApplicationRequest request,
    IPublicOnboardingService publicOnboardingService) =>
{
    return Results.Ok(publicOnboardingService.CreateSupplierApplication(request));
});

app.MapPost("/api/v1/public/onboarding/customers", (
    CreatePublicCustomerOnboardingApplicationRequest request,
    IPublicOnboardingService publicOnboardingService) =>
{
    return Results.Ok(publicOnboardingService.CreateCustomerApplication(request));
});

app.MapPost("/api/v1/public/onboarding/suppliers/evaluate", (
    CreatePublicSupplierOnboardingApplicationRequest request,
    IPublicOnboardingPolicyService onboardingPolicyService) =>
{
    return Results.Ok(onboardingPolicyService.EvaluateSupplierApplication(request));
});

app.MapPost("/api/v1/public/onboarding/customers/evaluate", (
    CreatePublicCustomerOnboardingApplicationRequest request,
    IPublicOnboardingPolicyService onboardingPolicyService) =>
{
    return Results.Ok(onboardingPolicyService.EvaluateCustomerApplication(request));
});

app.MapGet("/api/v1/public/privacy/governance", (
    string? subjectTypeCode,
    IPrivacyGovernanceService privacyGovernanceService) =>
{
    return Results.Ok(privacyGovernanceService.GetGovernance(subjectTypeCode));
});

app.MapPost("/api/v1/public/onboarding/compliance-documents/upload", async (
    HttpRequest request,
    IManagedComplianceDocumentUploadService managedComplianceDocumentUploadService,
    CancellationToken cancellationToken) =>
{
    var uploadRequest = await ReadComplianceUploadRequestAsync(request, cancellationToken);
    using var input = uploadRequest.File.OpenReadStream();
    var upload = await managedComplianceDocumentUploadService.UploadAsync(
        NormalizeUploadScope("public", uploadRequest.SubjectTypeCode),
        uploadRequest.DocumentType,
        uploadRequest.File.FileName,
        uploadRequest.File.ContentType,
        input,
        uploadRequest.File.Length,
        cancellationToken);

    return Results.Ok(new ComplianceDocumentUploadResponse(
        upload.DocumentType,
        upload.FileName,
        upload.StorageReference,
        upload.StorageProviderCode,
        upload.ContentType,
        upload.FileSizeBytes));
});

app.MapGet("/api/v1/auth/me", (ClaimsPrincipal user, IIdentityService identityService) =>
{
    return Results.Ok(identityService.GetCurrentUserProfile(CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/demo/bootstrap", (IConfiguration configuration, IHostEnvironment environment) =>
{
    if (!DemoUatBootstrapper.IsEnabled(configuration, environment))
    {
        return Results.NotFound();
    }

    return Results.Ok(DemoUatBootstrapper.BuildBootstrapResponse(configuration));
});

app.MapGet("/api/v1/documents", (
    string? moduleCode,
    string? entityName,
    long? entityId,
    string? lifecycleStatusCode,
    string? attachmentCategoryCode,
    IDocumentStorageService documentStorageService) =>
{
    return Results.Ok(documentStorageService.GetDocuments(moduleCode, entityName, entityId, lifecycleStatusCode, attachmentCategoryCode));
});

app.MapGet("/api/v1/documents/{id:long}", (long id, IDocumentStorageService documentStorageService) =>
{
    var document = documentStorageService.GetDocument(id);
    return document is null ? Results.NotFound() : Results.Ok(document);
});

app.MapPost("/api/v1/documents", (
    ClaimsPrincipal user,
    CreateDocumentAttachmentRequest request,
    IDocumentStorageService documentStorageService) =>
{
    return Results.Ok(documentStorageService.CreateDocument(CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/documents/{id:long}/archive", (
    long id,
    ClaimsPrincipal user,
    ArchiveDocumentAttachmentRequest request,
    IDocumentStorageService documentStorageService) =>
{
    return Results.Ok(documentStorageService.ArchiveDocument(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/documents/{id:long}/supersede", (
    long id,
    ClaimsPrincipal user,
    SupersedeDocumentAttachmentRequest request,
    IDocumentStorageService documentStorageService) =>
{
    return Results.Ok(documentStorageService.SupersedeDocument(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/iam/roles", (IIdentityService identityService) =>
{
    return Results.Ok(identityService.GetRoles());
});

app.MapGet("/api/v1/iam/function-configuration", (ClaimsPrincipal user, IAdminUserService adminUserService) =>
{
    var configuration = adminUserService.GetFunctionConfiguration();
    if (!IsSystemOwnerOnlyIdentity(user))
    {
        return Results.Ok(configuration);
    }

    return Results.Ok(configuration with
    {
        ExternalRoles = Array.Empty<AdminRoleFunctionOptionResponse>(),
        InternalRoles = configuration.InternalRoles
            .Where(role =>
                string.Equals(role.RoleCode, "SUPER_ADMIN", StringComparison.OrdinalIgnoreCase)
                || string.Equals(role.RoleCode, "ACCOUNTING_OFFICE_USER", StringComparison.OrdinalIgnoreCase)
                || string.Equals(role.RoleCode, "ACCOUNTING_OFFICE_SUPERVISOR", StringComparison.OrdinalIgnoreCase))
            .ToArray(),
        PortalMenuSections = configuration.PortalMenuSections
            .Where(IsSystemOwnerVisibleMenuSection)
            .ToArray()
    });
});

app.MapGet("/api/v1/iam/function-options", (ClaimsPrincipal user, string? userTypeCode, IAdminUserService adminUserService) =>
{
    var options = adminUserService.GetRoleFunctionOptions(userTypeCode);
    return Results.Ok(IsSystemOwnerOnlyIdentity(user)
        ? options.Where(option =>
            string.Equals(option.RoleCode, "SUPER_ADMIN", StringComparison.OrdinalIgnoreCase)
            || string.Equals(option.RoleCode, "ACCOUNTING_OFFICE_USER", StringComparison.OrdinalIgnoreCase)
            || string.Equals(option.RoleCode, "ACCOUNTING_OFFICE_SUPERVISOR", StringComparison.OrdinalIgnoreCase)).ToArray()
        : options);
});

app.MapPut("/api/v1/iam/function-governance", (
    ClaimsPrincipal user,
    UpdateAdminFunctionGovernanceRequest request,
    IAdminUserService adminUserService) =>
{
    if (IsSystemOwnerOnlyIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(adminUserService.UpdateFunctionGovernance(request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/iam/users", (
    ClaimsPrincipal user,
    string? userTypeCode,
    bool? includeInactive,
    IAdminUserService adminUserService) =>
{
    var users = adminUserService.GetUsers(userTypeCode, includeInactive ?? true);
    return Results.Ok(IsSystemOwnerOnlyIdentity(user)
        ? users.Where(IsSystemOwnerManagedUser).ToArray()
        : users);
});

app.MapGet("/api/v1/iam/users/{id:long}", (long id, ClaimsPrincipal user, IAdminUserService adminUserService) =>
{
    var managedUser = adminUserService.GetUser(id);
    if (managedUser is null)
    {
        return Results.NotFound();
    }

    if (IsSystemOwnerOnlyIdentity(user) && !IsSystemOwnerManagedUser(managedUser))
    {
        return Results.Forbid();
    }

    return Results.Ok(managedUser);
});

app.MapPost("/api/v1/iam/users", (
    ClaimsPrincipal user,
    CreateAdminManagedUserRequest request,
    IAdminUserService adminUserService) =>
{
    var authorityValidation = ValidateAdministratorCreationAuthority(user, request);
    if (authorityValidation is not null)
    {
        return Results.BadRequest(new { message = authorityValidation });
    }

    return Results.Ok(adminUserService.CreateUser(request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPut("/api/v1/iam/users/{id:long}/roles", (
    long id,
    ClaimsPrincipal user,
    UpdateAdminManagedUserRolesRequest request,
    IAdminUserService adminUserService) =>
{
    if (IsSystemOwnerOnlyIdentity(user))
    {
        return Results.Forbid();
    }

    var authorityValidation = ValidateAdministratorGovernanceAuthority(user, adminUserService.GetUser(id), request.RoleCodes);
    if (authorityValidation is not null)
    {
        return Results.BadRequest(new { message = authorityValidation });
    }

    return Results.Ok(adminUserService.ReplaceRoles(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/iam/users/{id:long}/suspend", (
    long id,
    ClaimsPrincipal user,
    AdminUserLifecycleActionRequest request,
    IAdminUserService adminUserService) =>
{
    if (IsSystemOwnerOnlyIdentity(user))
    {
        return Results.Forbid();
    }

    var authorityValidation = ValidateAdministratorGovernanceAuthority(user, adminUserService.GetUser(id), null);
    if (authorityValidation is not null)
    {
        return Results.BadRequest(new { message = authorityValidation });
    }

    return Results.Ok(adminUserService.SuspendUser(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/iam/users/{id:long}/hold", (
    long id,
    ClaimsPrincipal user,
    AdminUserLifecycleActionRequest request,
    IAdminUserService adminUserService) =>
{
    if (IsSystemOwnerOnlyIdentity(user))
    {
        return Results.Forbid();
    }

    var authorityValidation = ValidateAdministratorGovernanceAuthority(user, adminUserService.GetUser(id), null);
    if (authorityValidation is not null)
    {
        return Results.BadRequest(new { message = authorityValidation });
    }

    return Results.Ok(adminUserService.HoldUser(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/iam/users/{id:long}/reinstate", (
    long id,
    ClaimsPrincipal user,
    AdminUserLifecycleActionRequest request,
    IAdminUserService adminUserService) =>
{
    if (IsSystemOwnerOnlyIdentity(user))
    {
        return Results.Forbid();
    }

    var authorityValidation = ValidateAdministratorGovernanceAuthority(user, adminUserService.GetUser(id), null);
    if (authorityValidation is not null)
    {
        return Results.BadRequest(new { message = authorityValidation });
    }

    return Results.Ok(adminUserService.ReinstateUser(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/iam/users/{id:long}/revoke", (
    long id,
    ClaimsPrincipal user,
    AdminUserLifecycleActionRequest request,
    IAdminUserService adminUserService) =>
{
    if (IsSystemOwnerOnlyIdentity(user))
    {
        return Results.Forbid();
    }

    var authorityValidation = ValidateAdministratorGovernanceAuthority(user, adminUserService.GetUser(id), null);
    if (authorityValidation is not null)
    {
        return Results.BadRequest(new { message = authorityValidation });
    }

    return Results.Ok(adminUserService.RevokeUser(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapDelete("/api/v1/iam/users/{id:long}", (
    long id,
    ClaimsPrincipal user,
    [FromBody] AdminUserLifecycleActionRequest request,
    IAdminUserService adminUserService) =>
{
    if (IsSystemOwnerOnlyIdentity(user))
    {
        return Results.Forbid();
    }

    var authorityValidation = ValidateAdministratorGovernanceAuthority(user, adminUserService.GetUser(id), null);
    if (authorityValidation is not null)
    {
        return Results.BadRequest(new { message = authorityValidation });
    }

    return Results.Ok(adminUserService.DeleteUser(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/iam/parties", (
    string? partyType,
    IPartyOnboardingService partyOnboardingService) =>
{
    return Results.Ok(partyOnboardingService.GetParties(partyType));
});

app.MapGet("/api/v1/internal/parties/missing-firm-national-id", (
    ClaimsPrincipal user,
    IPartyOnboardingService partyOnboardingService) =>
{
    if (!HasAnyRole(user, "SUPER_ADMIN", "ADMIN", "ERP_OPS_MAKER", "FINANCE_MAKER", "FINANCE_CHECKER"))
    {
        return Results.Forbid();
    }

    return Results.Ok(partyOnboardingService.GetActiveClientsMissingFirmNationalId());
});

app.MapPut("/api/v1/internal/parties/{partyId:long}/firm-national-id", (
    long partyId,
    ClaimsPrincipal user,
    SetFirmNationalIdRequest request,
    IPartyOnboardingService partyOnboardingService) =>
{
    if (!HasAnyRole(user, "SUPER_ADMIN", "ADMIN", "ERP_OPS_MAKER"))
    {
        return Results.Forbid();
    }

    return Results.Ok(partyOnboardingService.SetFirmNationalId(
        partyId,
        request.FirmNationalId,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/iam/accounting-office-users/{id:long}/client-assignments", (
    long id,
    ClaimsPrincipal user,
    IAdminUserService adminUserService,
    IAccountingOfficeService accountingOfficeService) =>
{
    var authorityValidation = ValidateAdministratorGovernanceAuthority(user, adminUserService.GetUser(id), null);
    if (authorityValidation is not null)
    {
        return Results.BadRequest(new { message = authorityValidation });
    }

    return Results.Ok(accountingOfficeService.GetAssignments(id));
});

app.MapPost("/api/v1/iam/accounting-office-users/{id:long}/client-assignments", (
    long id,
    ClaimsPrincipal user,
    AssignAccountingOfficeClientRequest request,
    IAdminUserService adminUserService,
    IAccountingOfficeService accountingOfficeService) =>
{
    var authorityValidation = ValidateAdministratorGovernanceAuthority(user, adminUserService.GetUser(id), null);
    if (authorityValidation is not null)
    {
        return Results.BadRequest(new { message = authorityValidation });
    }

    return Results.Ok(accountingOfficeService.AssignClient(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapDelete("/api/v1/iam/accounting-office-users/{id:long}/client-assignments/{partyId:long}", (
    long id,
    long partyId,
    ClaimsPrincipal user,
    IAdminUserService adminUserService,
    IAccountingOfficeService accountingOfficeService) =>
{
    var authorityValidation = ValidateAdministratorGovernanceAuthority(user, adminUserService.GetUser(id), null);
    if (authorityValidation is not null)
    {
        return Results.BadRequest(new { message = authorityValidation });
    }

    accountingOfficeService.RemoveClient(id, partyId, CurrentUserAccessor.GetRequiredUserId(user));
    return Results.NoContent();
});

app.MapGet("/api/v1/iam/reports/users", (ClaimsPrincipal user, string? userTypeCode, IAdminUserService adminUserService) =>
{
    var effectiveRoleCode = IsSystemOwnerOnlyIdentity(user)
        ? "SUPER_ADMIN,ACCOUNTING_OFFICE_USER,ACCOUNTING_OFFICE_SUPERVISOR"
        : null;
    return Results.Ok(adminUserService.GetUserAdministrationReportRows(
        IsSystemOwnerOnlyIdentity(user) ? "INTERNAL" : userTypeCode,
        effectiveRoleCode));
});

app.MapGet("/api/v1/iam/reports/users/export", (ClaimsPrincipal user, string? format, string? userTypeCode, IAdminUserService adminUserService) =>
{
    var effectiveUserTypeCode = IsSystemOwnerOnlyIdentity(user) ? "INTERNAL" : userTypeCode;
    var effectiveRoleCode = IsSystemOwnerOnlyIdentity(user)
        ? "SUPER_ADMIN,ACCOUNTING_OFFICE_USER,ACCOUNTING_OFFICE_SUPERVISOR"
        : null;
    var actorUserId = CurrentUserAccessor.GetRequiredUserId(user);
    if (string.Equals(format, "PDF", StringComparison.OrdinalIgnoreCase))
    {
        return Results.File(
            adminUserService.ExportUserAdministrationReportPdf(actorUserId, effectiveUserTypeCode, effectiveRoleCode),
            "application/pdf",
            "cashline-user-administration-report.pdf");
    }

    return Results.File(
        System.Text.Encoding.UTF8.GetBytes(adminUserService.ExportUserAdministrationReportExcel(actorUserId, effectiveUserTypeCode, effectiveRoleCode)),
        "application/vnd.ms-excel",
        "cashline-user-administration-report.xls");
});

app.MapGet("/api/v1/iam/privacy/governance", (
    ClaimsPrincipal user,
    string? subjectTypeCode,
    IPrivacyGovernanceService privacyGovernanceService) =>
{
    if (IsSystemOwnerOnlyIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(privacyGovernanceService.GetGovernance(subjectTypeCode));
});

app.MapGet("/api/v1/accounting-office/clients", (
    ClaimsPrincipal user,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.GetCurrentUserClients(CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/accounting-office/clients/{partyId:long}/workspace", (
    long partyId,
    ClaimsPrincipal user,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.GetCurrentUserClientWorkspace(CurrentUserAccessor.GetRequiredUserId(user), partyId));
});

app.MapGet("/api/v1/accounting-office/clients/{partyId:long}/requests", (
    long partyId,
    ClaimsPrincipal user,
    IAccountingOfficeClientRequestService accountingOfficeClientRequestService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeClientRequestService.GetAccountingOfficeClientRequests(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId));
});

app.MapPost("/api/v1/accounting-office/clients/{partyId:long}/requests/{requestId:long}/start-review", (
    long partyId,
    long requestId,
    ClaimsPrincipal user,
    ReviewAccountingOfficeClientRequestRequest request,
    IAccountingOfficeClientRequestService accountingOfficeClientRequestService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeClientRequestService.StartReview(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        requestId,
        request));
});

app.MapPost("/api/v1/accounting-office/clients/{partyId:long}/requests/{requestId:long}/complete", (
    long partyId,
    long requestId,
    ClaimsPrincipal user,
    CompleteAccountingOfficeClientRequestRequest request,
    IAccountingOfficeClientRequestService accountingOfficeClientRequestService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeClientRequestService.Complete(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        requestId,
        request));
});

app.MapPost("/api/v1/accounting-office/clients/{partyId:long}/requests/{requestId:long}/reject", (
    long partyId,
    long requestId,
    ClaimsPrincipal user,
    RejectAccountingOfficeClientRequestRequest request,
    IAccountingOfficeClientRequestService accountingOfficeClientRequestService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeClientRequestService.Reject(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        requestId,
        request));
});

app.MapGet("/api/v1/accounting-office/clients/{partyId:long}/submission-posture", (
    long partyId,
    ClaimsPrincipal user,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.GetCurrentUserClientSubmissionPosture(CurrentUserAccessor.GetRequiredUserId(user), partyId));
});

app.MapPost("/api/v1/accounting-office/clients/{partyId:long}/compliance-documents/upload", async (
    long partyId,
    HttpRequest request,
    ClaimsPrincipal user,
    IManagedComplianceDocumentUploadService managedComplianceDocumentUploadService,
    IAccountingOfficeService accountingOfficeService,
    CancellationToken cancellationToken) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    var uploadRequest = await ReadComplianceUploadRequestAsync(request, cancellationToken);
    using var input = uploadRequest.File.OpenReadStream();
    var upload = await managedComplianceDocumentUploadService.UploadAsync(
        NormalizeUploadScope($"accounting-office-party-{partyId}", uploadRequest.SubjectTypeCode),
        uploadRequest.DocumentType,
        uploadRequest.File.FileName,
        uploadRequest.File.ContentType,
        input,
        uploadRequest.File.Length,
        cancellationToken);

    return Results.Ok(accountingOfficeService.RecordCurrentUserClientComplianceDocument(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        new RecordBusinessPartyComplianceDocumentRequest(
            upload.DocumentType,
            upload.FileName,
            upload.StorageReference,
            upload.ContentType,
            upload.FileSizeBytes)));
});

app.MapGet("/api/v1/accounting-office/clients/{partyId:long}/ar-invoices/{invoiceId:long}/eta-validation-pack", (
    long partyId,
    long invoiceId,
    ClaimsPrincipal user,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    var pack = accountingOfficeService.GetCurrentUserClientInvoiceEtaValidationPack(CurrentUserAccessor.GetRequiredUserId(user), partyId, invoiceId);
    return pack is null ? Results.NotFound() : Results.Ok(pack);
});

app.MapGet("/api/v1/accounting-office/clients/{partyId:long}/ar-invoices/{invoiceId:long}/eta-submissions", (
    long partyId,
    long invoiceId,
    ClaimsPrincipal user,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.GetCurrentUserClientInvoiceEtaSubmissionLogs(CurrentUserAccessor.GetRequiredUserId(user), partyId, invoiceId));
});

app.MapPost("/api/v1/accounting-office/clients/{partyId:long}/ar-invoices/{invoiceId:long}/eta-submit", (
    long partyId,
    long invoiceId,
    ClaimsPrincipal user,
    SubmitInvoiceToEtaRequest request,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.SubmitCurrentUserClientInvoiceToEta(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        invoiceId,
        request));
});

app.MapGet("/api/v1/accounting-office/clients/{partyId:long}/statements", (
    long partyId,
    ClaimsPrincipal user,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.GetCurrentUserClientStatementDocuments(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId));
});

app.MapPost("/api/v1/accounting-office/clients/{partyId:long}/statements/generate", (
    long partyId,
    ClaimsPrincipal user,
    GenerateAccountingOfficeClientStatementRequest request,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.GenerateCurrentUserClientStatement(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        request));
});

app.MapGet("/api/v1/accounting-office/clients/{partyId:long}/statements/{statementId:long}/delivery-logs", (
    long partyId,
    long statementId,
    ClaimsPrincipal user,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.GetCurrentUserClientStatementDeliveryLogs(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        statementId));
});

app.MapPost("/api/v1/accounting-office/clients/{partyId:long}/statements/{statementId:long}/delivery-logs", (
    long partyId,
    long statementId,
    ClaimsPrincipal user,
    RecordAccountingOfficeClientStatementDeliveryRequest request,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.RecordCurrentUserClientStatementDelivery(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        statementId,
        request));
});

app.MapPost("/api/v1/accounting-office/clients/{partyId:long}/statements/{statementId:long}/delivery-logs/{deliveryLogId:long}/acknowledge", (
    long partyId,
    long statementId,
    long deliveryLogId,
    ClaimsPrincipal user,
    AcknowledgeAccountingOfficeClientStatementDeliveryRequest request,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.AcknowledgeCurrentUserClientSupplierStatementDelivery(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        statementId,
        deliveryLogId,
        request));
});

app.MapPost("/api/v1/accounting-office/clients/{partyId:long}/statements/{statementId:long}/delivery-logs/{deliveryLogId:long}/retry", (
    long partyId,
    long statementId,
    long deliveryLogId,
    ClaimsPrincipal user,
    RetryAccountingOfficeClientStatementDeliveryRequest request,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.RetryCurrentUserClientStatementDelivery(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        statementId,
        deliveryLogId,
        request));
});

app.MapGet("/api/v1/accounting-office/clients/{partyId:long}/report-export", (
    long partyId,
    ClaimsPrincipal user,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Text(
        accountingOfficeService.ExportCurrentUserClientReportCsv(CurrentUserAccessor.GetRequiredUserId(user), partyId),
        "text/csv");
});

app.MapGet("/api/v1/accounting-office/activity", (
    ClaimsPrincipal user,
    long? partyId,
    IAccountingOfficeService accountingOfficeService) =>
{
    if (!IsAccountingOfficeIdentity(user))
    {
        return Results.Forbid();
    }

    return Results.Ok(accountingOfficeService.GetCurrentUserActivity(CurrentUserAccessor.GetRequiredUserId(user), partyId));
});

app.MapGet("/api/v1/parties", (string? partyType, IPartyOnboardingService partyOnboardingService) =>
{
    return Results.Ok(partyOnboardingService.GetParties(partyType));
});

app.MapGet("/api/v1/onboarding/policies/suppliers", (
    string? onboardingPathCode,
    IPublicOnboardingPolicyService onboardingPolicyService) =>
{
    return Results.Ok(onboardingPolicyService.GetSupplierPolicy(onboardingPathCode ?? "PUBLIC_SELF_INITIATED"));
});

app.MapGet("/api/v1/onboarding/policies/customers", (
    string? onboardingPathCode,
    IPublicOnboardingPolicyService onboardingPolicyService) =>
{
    return Results.Ok(onboardingPolicyService.GetCustomerPolicy(onboardingPathCode ?? "PUBLIC_SELF_INITIATED"));
});

app.MapGet("/api/v1/internal/onboarding/cases", (
    ClaimsPrincipal user,
    string? subjectTypeCode,
    string? caseStatusCode,
    string? queueCode,
    IOnboardingCaseService onboardingCaseService) =>
{
    var submittedByUserId = IsAccountingOfficeIdentity(user)
        ? CurrentUserAccessor.GetRequiredUserId(user)
        : (long?)null;
    return Results.Ok(onboardingCaseService.GetCases(subjectTypeCode, caseStatusCode, queueCode, submittedByUserId));
});

app.MapGet("/api/v1/internal/onboarding/cases/{subjectTypeCode}/{subjectProfileId:long}", (
    ClaimsPrincipal user,
    string subjectTypeCode,
    long subjectProfileId,
    IOnboardingCaseService onboardingCaseService) =>
{
    var submittedByUserId = IsAccountingOfficeIdentity(user)
        ? CurrentUserAccessor.GetRequiredUserId(user)
        : (long?)null;
    var onboardingCase = onboardingCaseService.GetCase(subjectTypeCode, subjectProfileId, submittedByUserId);
    return onboardingCase is null ? Results.NotFound() : Results.Ok(onboardingCase);
});

app.MapGet("/api/v1/internal/onboarding/leads", (
    ClaimsPrincipal user,
    string? prospectTypeCode,
    string? statusCode,
    IOnboardingLeadService onboardingLeadService) =>
{
    if (IsAccountingOfficeIdentity(user))
    {
        return Results.Ok(Array.Empty<OnboardingLeadSummaryResponse>());
    }

    return Results.Ok(onboardingLeadService.GetLeads(prospectTypeCode, statusCode));
});

app.MapPost("/api/v1/internal/onboarding/suppliers", (
    ClaimsPrincipal user,
    CreateInternalSupplierOnboardingRequest request,
    IInternalOnboardingIntakeService internalOnboardingIntakeService) =>
{
    return Results.Ok(internalOnboardingIntakeService.CreateSupplierApplication(
        request,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/internal/onboarding/customers", (
    ClaimsPrincipal user,
    CreateInternalCustomerOnboardingRequest request,
    IInternalOnboardingIntakeService internalOnboardingIntakeService) =>
{
    return Results.Ok(internalOnboardingIntakeService.CreateCustomerApplication(
        request,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/parties", (CreateBusinessPartyRequest request, IPartyOnboardingService partyOnboardingService) =>
{
    return Results.Ok(partyOnboardingService.CreateParty(request));
});

app.MapGet("/api/v1/parties/{partyId:long}/compliance-documents", (long partyId, IPartyOnboardingService partyOnboardingService) =>
{
    return Results.Ok(partyOnboardingService.GetComplianceDocuments(partyId));
});

app.MapPost("/api/v1/parties/{partyId:long}/compliance-documents", (
    long partyId,
    ClaimsPrincipal user,
    RecordBusinessPartyComplianceDocumentRequest request,
    IPartyOnboardingService partyOnboardingService) =>
{
    return Results.Ok(partyOnboardingService.RecordComplianceDocument(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        request));
});

app.MapPost("/api/v1/parties/{partyId:long}/compliance-documents/upload", async (
    long partyId,
    HttpRequest request,
    ClaimsPrincipal user,
    IManagedComplianceDocumentUploadService managedComplianceDocumentUploadService,
    IPartyOnboardingService partyOnboardingService,
    CancellationToken cancellationToken) =>
{
    CurrentUserAccessor.EnsureInternalUser(user);

    var uploadRequest = await ReadComplianceUploadRequestAsync(request, cancellationToken);
    using var input = uploadRequest.File.OpenReadStream();
    var upload = await managedComplianceDocumentUploadService.UploadAsync(
        $"internal-party-{partyId}",
        uploadRequest.DocumentType,
        uploadRequest.File.FileName,
        uploadRequest.File.ContentType,
        input,
        uploadRequest.File.Length,
        cancellationToken);

    return Results.Ok(partyOnboardingService.RecordComplianceDocument(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        new RecordBusinessPartyComplianceDocumentRequest(
            upload.DocumentType,
            upload.FileName,
            upload.StorageReference,
            upload.ContentType,
            upload.FileSizeBytes)));
});

app.MapGet("/api/v1/suppliers/{id:long}/document-workflows", (long id, IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetDocumentWorkflows(id));
});

app.MapGet("/api/v1/customers/{id:long}/document-workflows", (long id, IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetDocumentWorkflows(id));
});

app.MapPost("/api/v1/suppliers/document-workflows/{workflowId:long}/approve", (
    long workflowId,
    ClaimsPrincipal user,
    ReviewExternalDocumentWorkflowRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.ApproveDocumentWorkflow(
        workflowId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/suppliers/document-workflows/{workflowId:long}/return", (
    long workflowId,
    ClaimsPrincipal user,
    ReviewExternalDocumentWorkflowRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.ReturnDocumentWorkflow(
        workflowId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/suppliers/document-workflows/{workflowId:long}/reject", (
    long workflowId,
    ClaimsPrincipal user,
    ReviewExternalDocumentWorkflowRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.RejectDocumentWorkflow(
        workflowId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/customers/document-workflows/{workflowId:long}/approve", (
    long workflowId,
    ClaimsPrincipal user,
    ReviewExternalDocumentWorkflowRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.ApproveDocumentWorkflow(
        workflowId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/customers/document-workflows/{workflowId:long}/return", (
    long workflowId,
    ClaimsPrincipal user,
    ReviewExternalDocumentWorkflowRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.ReturnDocumentWorkflow(
        workflowId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/customers/document-workflows/{workflowId:long}/reject", (
    long workflowId,
    ClaimsPrincipal user,
    ReviewExternalDocumentWorkflowRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.RejectDocumentWorkflow(
        workflowId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapGet("/api/v1/suppliers", (
    bool? activeOnly,
    string? statusCode,
    long? businessPartyId,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.GetSupplierProfiles(activeOnly ?? false, statusCode, businessPartyId));
});

app.MapGet("/api/v1/suppliers/{id:long}", (long id, ISupplierProfileService supplierProfileService) =>
{
    var supplier = supplierProfileService.GetSupplierProfile(id);
    return supplier is null ? Results.NotFound() : Results.Ok(supplier);
});

app.MapPost("/api/v1/suppliers", (
    CreateSupplierProfileRequest request,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.CreateSupplierProfile(request));
});

app.MapPost("/api/v1/suppliers/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.SubmitSupplierProfile(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/suppliers/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.ApproveSupplierProfile(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/suppliers/{id:long}/return", (
    long id,
    ClaimsPrincipal user,
    ReviewSupplierProfileRequest request,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.ReturnSupplierProfile(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/suppliers/{id:long}/reject", (
    long id,
    ClaimsPrincipal user,
    ReviewSupplierProfileRequest request,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.RejectSupplierProfile(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/suppliers/{id:long}/hold", (
    long id,
    ClaimsPrincipal user,
    HoldSupplierProfileRequest request,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.HoldSupplierProfile(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/suppliers/{id:long}/reopen", (
    long id,
    ClaimsPrincipal user,
    ReopenSupplierProfileRequest request,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.ReopenSupplierProfile(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/suppliers/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.ActivateSupplierProfile(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/suppliers/{id:long}/verify-bank", (
    long id,
    ClaimsPrincipal user,
    VerifySupplierBankRequest request,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.VerifySupplierBank(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/suppliers/{id:long}/performance-review", (
    long id,
    ClaimsPrincipal user,
    RecordSupplierPerformanceReviewRequest request,
    ISupplierProfileService supplierProfileService) =>
{
    return Results.Ok(supplierProfileService.RecordPerformanceReview(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/suppliers/{id:long}/onboarding-review", (
    long id,
    IOnboardingReviewService onboardingReviewService) =>
{
    return Results.Ok(onboardingReviewService.GetSupplierReviewCase(id));
});

app.MapPost("/api/v1/suppliers/{id:long}/onboarding-review/checklist-items", (
    long id,
    ClaimsPrincipal user,
    IReadOnlyCollection<UpsertOnboardingReviewChecklistItemRequest> request,
    IOnboardingReviewService onboardingReviewService) =>
{
    return Results.Ok(onboardingReviewService.UpsertSupplierChecklistItems(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/suppliers/{id:long}/onboarding-review/findings", (
    long id,
    ClaimsPrincipal user,
    CreateOnboardingReviewFindingRequest request,
    IOnboardingReviewService onboardingReviewService) =>
{
    return Results.Ok(onboardingReviewService.AddSupplierFinding(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/customers", (
    bool? activeOnly,
    string? statusCode,
    long? businessPartyId,
    string? classificationCode,
    ICustomerProfileService customerProfileService) =>
{
    return Results.Ok(customerProfileService.GetCustomerProfiles(activeOnly ?? false, statusCode, businessPartyId, classificationCode));
});

app.MapGet("/api/v1/customers/{id:long}", (long id, ICustomerProfileService customerProfileService) =>
{
    var customer = customerProfileService.GetCustomerProfile(id);
    return customer is null ? Results.NotFound() : Results.Ok(customer);
});

app.MapPost("/api/v1/customers", (
    CreateCustomerProfileRequest request,
    ICustomerProfileService customerProfileService) =>
{
    return Results.Ok(customerProfileService.CreateCustomerProfile(request));
});

app.MapPost("/api/v1/customers/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    ICustomerProfileService customerProfileService) =>
{
    return Results.Ok(customerProfileService.SubmitCustomerProfile(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/customers/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    ICustomerProfileService customerProfileService) =>
{
    return Results.Ok(customerProfileService.ApproveCustomerProfile(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/customers/{id:long}/return", (
    long id,
    ClaimsPrincipal user,
    ReviewCustomerProfileRequest request,
    ICustomerProfileService customerProfileService) =>
{
    return Results.Ok(customerProfileService.ReturnCustomerProfile(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/customers/{id:long}/reject", (
    long id,
    ClaimsPrincipal user,
    ReviewCustomerProfileRequest request,
    ICustomerProfileService customerProfileService) =>
{
    return Results.Ok(customerProfileService.RejectCustomerProfile(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/customers/{id:long}/hold", (
    long id,
    ClaimsPrincipal user,
    HoldCustomerProfileRequest request,
    ICustomerProfileService customerProfileService) =>
{
    return Results.Ok(customerProfileService.HoldCustomerProfile(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/customers/{id:long}/reopen", (
    long id,
    ClaimsPrincipal user,
    ReopenCustomerProfileRequest request,
    ICustomerProfileService customerProfileService) =>
{
    return Results.Ok(customerProfileService.ReopenCustomerProfile(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/customers/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    ICustomerProfileService customerProfileService) =>
{
    return Results.Ok(customerProfileService.ActivateCustomerProfile(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/customers/{id:long}/onboarding-review", (
    long id,
    IOnboardingReviewService onboardingReviewService) =>
{
    return Results.Ok(onboardingReviewService.GetCustomerReviewCase(id));
});

app.MapPost("/api/v1/customers/{id:long}/onboarding-review/checklist-items", (
    long id,
    ClaimsPrincipal user,
    IReadOnlyCollection<UpsertOnboardingReviewChecklistItemRequest> request,
    IOnboardingReviewService onboardingReviewService) =>
{
    return Results.Ok(onboardingReviewService.UpsertCustomerChecklistItems(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/customers/{id:long}/onboarding-review/findings", (
    long id,
    ClaimsPrincipal user,
    CreateOnboardingReviewFindingRequest request,
    IOnboardingReviewService onboardingReviewService) =>
{
    return Results.Ok(onboardingReviewService.AddCustomerFinding(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/customers/{id:long}/service-requests", (long id, IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetCustomerServiceRequests(id));
});

app.MapPost("/api/v1/customers/service-requests/{serviceRequestId:long}/review", (
    long serviceRequestId,
    ClaimsPrincipal user,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.StartCustomerServiceRequestReview(
        serviceRequestId,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/customers/service-requests/{serviceRequestId:long}/route", (
    long serviceRequestId,
    ClaimsPrincipal user,
    RouteExternalCustomerServiceRequestRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.RouteCustomerServiceRequest(
        serviceRequestId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/customers/service-requests/{serviceRequestId:long}/respond", (
    long serviceRequestId,
    ClaimsPrincipal user,
    ReviewExternalCustomerServiceRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.RespondToCustomerServiceRequest(
        serviceRequestId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/customers/service-requests/{serviceRequestId:long}/reject", (
    long serviceRequestId,
    ClaimsPrincipal user,
    ReviewExternalCustomerServiceRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.RejectCustomerServiceRequest(
        serviceRequestId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/customers/service-requests/{serviceRequestId:long}/close", (
    long serviceRequestId,
    ClaimsPrincipal user,
    CloseExternalCustomerServiceRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.CloseCustomerServiceRequest(
        serviceRequestId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapGet("/api/v1/workflow/queue", (IWorkflowService workflowService) =>
{
    return Results.Ok(workflowService.GetPendingQueue());
});

app.MapGet("/api/v1/workflow/rules", (bool? activeOnly, IWorkflowService workflowService) =>
{
    return Results.Ok(workflowService.GetWorkflowRules(activeOnly ?? false));
});

app.MapGet("/api/v1/workflow/instances", (string? moduleCode, string? documentType, string? statusCode, IWorkflowService workflowService) =>
{
    return Results.Ok(workflowService.GetWorkflowInstances(moduleCode, documentType, statusCode));
});

app.MapGet("/api/v1/workflow/instances/{id:long}", (long id, IWorkflowService workflowService) =>
{
    var instance = workflowService.GetWorkflowInstance(id);
    return instance is null ? Results.NotFound() : Results.Ok(instance);
});

app.MapGet("/api/v1/internal/dashboard", (IInternalWorkbenchService internalWorkbenchService) =>
{
    return Results.Ok(internalWorkbenchService.GetDashboardSummary());
});

app.MapGet("/api/v1/internal/operations/dashboard", (
    IHostEnvironment environment,
    IInternalWorkbenchService internalWorkbenchService) =>
{
    var buildVersion = typeof(Program).Assembly.GetName().Version?.ToString() ?? "0.0.0";
    return Results.Ok(internalWorkbenchService.GetOperationalDashboard(environment.EnvironmentName, buildVersion));
});

app.MapGet("/api/v1/internal/workflow-monitoring", (
    int? itemLimit,
    IHostEnvironment environment,
    IInternalWorkbenchService internalWorkbenchService) =>
{
    var buildVersion = typeof(Program).Assembly.GetName().Version?.ToString() ?? "0.0.0";
    return Results.Ok(internalWorkbenchService.GetWorkflowMonitoring(environment.EnvironmentName, buildVersion, itemLimit ?? 10));
});

app.MapGet("/api/v1/internal/operations/alerts", (
    string? severityCode,
    string? sourceArea,
    IInternalWorkbenchService internalWorkbenchService) =>
{
    return Results.Ok(internalWorkbenchService.GetOperationalAlerts(severityCode, sourceArea));
});

app.MapGet("/api/v1/internal/hypercare/console", (
    IHostEnvironment environment,
    IInternalWorkbenchService internalWorkbenchService) =>
{
    var buildVersion = typeof(Program).Assembly.GetName().Version?.ToString() ?? "0.0.0";
    return Results.Ok(internalWorkbenchService.GetHypercareConsole(environment.EnvironmentName, buildVersion));
});

app.MapGet("/api/v1/internal/hypercare/incidents", (
    string? severityCode,
    string? sourceArea,
    IInternalWorkbenchService internalWorkbenchService) =>
{
    return Results.Ok(internalWorkbenchService.GetHypercareIncidents(severityCode, sourceArea));
});

app.MapGet("/api/v1/internal/hypercare/runbooks", (
    string? categoryCode,
    IInternalWorkbenchService internalWorkbenchService) =>
{
    return Results.Ok(internalWorkbenchService.GetHypercareRunbooks(categoryCode));
});

app.MapGet("/api/v1/internal/hypercare/runbooks/{runbookCode}", (
    string runbookCode,
    IInternalWorkbenchService internalWorkbenchService) =>
{
    var runbook = internalWorkbenchService.GetHypercareRunbook(runbookCode);
    return runbook is null ? Results.NotFound() : Results.Ok(runbook);
});

app.MapGet("/api/v1/localization/supported-cultures", (ILocalizationService localizationService) =>
{
    return Results.Ok(localizationService.GetSupportedCultures());
});

app.MapGet("/api/v1/localization/resource-packs/{resourceSetCode}", (
    string resourceSetCode,
    string? cultureCode,
    ILocalizationService localizationService) =>
{
    return Results.Ok(localizationService.GetResourcePack(resourceSetCode, cultureCode));
});

app.MapGet("/api/v1/admin/setup/overview", (IReferenceDataGovernanceService referenceDataGovernanceService) =>
{
    return Results.Ok(referenceDataGovernanceService.GetOverview());
});

app.MapGet("/api/v1/admin/setup/reference-data", (
    string? referenceTypeCode,
    bool activeOnly,
    IReferenceDataGovernanceService referenceDataGovernanceService) =>
{
    return Results.Ok(referenceDataGovernanceService.GetEntries(referenceTypeCode, activeOnly));
});

app.MapGet("/api/v1/admin/setup/reference-data/{id:long}", (long id, IReferenceDataGovernanceService referenceDataGovernanceService) =>
{
    var entry = referenceDataGovernanceService.GetEntry(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapPost("/api/v1/admin/setup/reference-data", (
    CreateReferenceDataEntryRequest request,
    IReferenceDataGovernanceService referenceDataGovernanceService) =>
{
    return Results.Ok(referenceDataGovernanceService.CreateReferenceDataEntry(request));
});

app.MapPost("/api/v1/admin/setup/reference-data/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IReferenceDataGovernanceService referenceDataGovernanceService) =>
{
    return Results.Ok(referenceDataGovernanceService.SubmitReferenceDataEntry(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/admin/setup/reference-data/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IReferenceDataGovernanceService referenceDataGovernanceService) =>
{
    return Results.Ok(referenceDataGovernanceService.ApproveReferenceDataEntry(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/admin/setup/reference-data/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    IReferenceDataGovernanceService referenceDataGovernanceService) =>
{
    return Results.Ok(referenceDataGovernanceService.ActivateReferenceDataEntry(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/partners", (
    bool? activeOnly,
    IIslamicFinancePartnerService islamicFinancePartnerService) =>
{
    return Results.Ok(islamicFinancePartnerService.GetPartnerLenders(activeOnly ?? false));
});

app.MapGet("/api/v1/islamic-finance/partners/{id:long}", (long id, IIslamicFinancePartnerService islamicFinancePartnerService) =>
{
    var entry = islamicFinancePartnerService.GetPartnerLender(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapPost("/api/v1/islamic-finance/partners", (
    CreateIslamicFinancePartnerLenderRequest request,
    IIslamicFinancePartnerService islamicFinancePartnerService) =>
{
    return Results.Ok(islamicFinancePartnerService.CreatePartnerLender(request));
});

app.MapPost("/api/v1/islamic-finance/partners/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinancePartnerService islamicFinancePartnerService) =>
{
    return Results.Ok(islamicFinancePartnerService.SubmitPartnerLender(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/partners/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinancePartnerService islamicFinancePartnerService) =>
{
    return Results.Ok(islamicFinancePartnerService.ApprovePartnerLender(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/partners/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinancePartnerService islamicFinancePartnerService) =>
{
    return Results.Ok(islamicFinancePartnerService.ActivatePartnerLender(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/product-profiles", (
    bool? activeOnly,
    string? productType,
    IIslamicFinanceProductService islamicFinanceProductService) =>
{
    return Results.Ok(islamicFinanceProductService.GetProductProfiles(activeOnly ?? false, productType));
});

app.MapGet("/api/v1/islamic-finance/product-profiles/{id:long}", (long id, IIslamicFinanceProductService islamicFinanceProductService) =>
{
    var entry = islamicFinanceProductService.GetProductProfile(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapPost("/api/v1/islamic-finance/product-profiles", (
    CreateIslamicFinanceProductProfileRequest request,
    IIslamicFinanceProductService islamicFinanceProductService) =>
{
    return Results.Ok(islamicFinanceProductService.CreateProductProfile(request));
});

app.MapPost("/api/v1/islamic-finance/product-profiles/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceProductService islamicFinanceProductService) =>
{
    return Results.Ok(islamicFinanceProductService.SubmitProductProfile(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/product-profiles/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceProductService islamicFinanceProductService) =>
{
    return Results.Ok(islamicFinanceProductService.ApproveProductProfile(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/product-profiles/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceProductService islamicFinanceProductService) =>
{
    return Results.Ok(islamicFinanceProductService.ActivateProductProfile(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/contract-templates", (
    bool? activeOnly,
    long? productProfileId,
    string? languageCode,
    IIslamicFinanceContractTemplateService islamicFinanceContractTemplateService) =>
{
    return Results.Ok(islamicFinanceContractTemplateService.GetContractTemplates(activeOnly ?? false, productProfileId, languageCode));
});

app.MapGet("/api/v1/islamic-finance/contract-templates/{id:long}", (
    long id,
    IIslamicFinanceContractTemplateService islamicFinanceContractTemplateService) =>
{
    var entry = islamicFinanceContractTemplateService.GetContractTemplate(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapPost("/api/v1/islamic-finance/contract-templates", (
    CreateIslamicFinanceContractTemplateRequest request,
    IIslamicFinanceContractTemplateService islamicFinanceContractTemplateService) =>
{
    return Results.Ok(islamicFinanceContractTemplateService.CreateContractTemplate(request));
});

app.MapPost("/api/v1/islamic-finance/contract-templates/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceContractTemplateService islamicFinanceContractTemplateService) =>
{
    return Results.Ok(islamicFinanceContractTemplateService.SubmitContractTemplate(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/contract-templates/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceContractTemplateService islamicFinanceContractTemplateService) =>
{
    return Results.Ok(islamicFinanceContractTemplateService.ApproveContractTemplate(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/contract-templates/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceContractTemplateService islamicFinanceContractTemplateService) =>
{
    return Results.Ok(islamicFinanceContractTemplateService.ActivateContractTemplate(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/facilities", (
    bool? activeOnly,
    long? customerPartyId,
    long? partnerLenderId,
    IIslamicFinanceFacilityService islamicFinanceFacilityService) =>
{
    return Results.Ok(islamicFinanceFacilityService.GetFacilities(activeOnly ?? false, customerPartyId, partnerLenderId));
});

app.MapGet("/api/v1/islamic-finance/facilities/{id:long}", (long id, IIslamicFinanceFacilityService islamicFinanceFacilityService) =>
{
    var entry = islamicFinanceFacilityService.GetFacility(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapPost("/api/v1/islamic-finance/facilities", (
    CreateIslamicFinanceFacilityRequest request,
    IIslamicFinanceFacilityService islamicFinanceFacilityService) =>
{
    return Results.Ok(islamicFinanceFacilityService.CreateFacility(request));
});

app.MapPost("/api/v1/islamic-finance/facilities/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceFacilityService islamicFinanceFacilityService) =>
{
    return Results.Ok(islamicFinanceFacilityService.SubmitFacility(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/facilities/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceFacilityService islamicFinanceFacilityService) =>
{
    return Results.Ok(islamicFinanceFacilityService.ApproveFacility(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/facilities/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceFacilityService islamicFinanceFacilityService) =>
{
    return Results.Ok(islamicFinanceFacilityService.ActivateFacility(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/requests", (
    string? statusCode,
    long? customerPartyId,
    long? productProfileId,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.GetRequests(statusCode, customerPartyId, productProfileId));
});

app.MapGet("/api/v1/islamic-finance/officer-workbench", (
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.GetOfficerWorkbench());
});

app.MapGet("/api/v1/islamic-finance/execution-workbench", (
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.GetExecutionWorkbench());
});

app.MapGet("/api/v1/islamic-finance/requests/{id:long}/partner-orchestration", (
    long id,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    var item = islamicFinanceRequestService.GetPartnerOrchestration(id);
    return item is null ? Results.NotFound() : Results.Ok(item);
});

app.MapGet("/api/v1/islamic-finance/requests/{id:long}", (long id, IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    var entry = islamicFinanceRequestService.GetRequest(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapGet("/api/v1/islamic-finance/requests/{id:long}/history", (long id, IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.GetRequestHistory(id));
});

app.MapGet("/api/v1/islamic-finance/requests/{id:long}/audit", (long id, IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    var audit = islamicFinanceRequestService.GetRequestAudit(id);
    return audit is null ? Results.NotFound() : Results.Ok(audit);
});

app.MapGet("/api/v1/islamic-finance/requests/{id:long}/decisions", (long id, IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.GetDecisions(id));
});

app.MapGet("/api/v1/islamic-finance/decisions/{id:long}", (long id, IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    var entry = islamicFinanceRequestService.GetDecision(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapGet("/api/v1/islamic-finance/decisions/{id:long}/audit", (long id, IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    var audit = islamicFinanceRequestService.GetDecisionAudit(id);
    return audit is null ? Results.NotFound() : Results.Ok(audit);
});

app.MapPost("/api/v1/islamic-finance/requests", (
    CreateIslamicFinanceFinancingRequestRequest request,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.CreateRequest(request));
});

app.MapPost("/api/v1/islamic-finance/requests/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.SubmitRequest(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/requests/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.ApproveRequest(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/requests/{id:long}/return", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.ReturnRequest(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/requests/{id:long}/reject", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.RejectRequest(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/requests/{id:long}/assign-partner-lender", (
    long id,
    ClaimsPrincipal user,
    AssignIslamicFinancePartnerLenderRequest request,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.AssignPartnerLender(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/requests/{id:long}/route-partners", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.RoutePartnerLenders(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/requests/{id:long}/attach-shariah-review", (
    long id,
    ClaimsPrincipal user,
    AttachIslamicFinanceShariahReviewRequest request,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.AttachShariahReview(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/requests/{id:long}/decisions", (
    long id,
    CreateIslamicFinanceDecisionRequest request,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.CreateDecision(id, request));
});

app.MapPost("/api/v1/islamic-finance/decisions/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.SubmitDecision(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/decisions/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.ApproveDecision(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/decisions/{id:long}/return", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.ReturnDecision(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/decisions/{id:long}/reject", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceRequestService islamicFinanceRequestService) =>
{
    return Results.Ok(islamicFinanceRequestService.RejectDecision(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/shariah-reviews", (
    string? statusCode,
    long? financingRequestId,
    long? productProfileId,
    IShariahReviewService shariahReviewService) =>
{
    return Results.Ok(shariahReviewService.GetReviewCases(statusCode, financingRequestId, productProfileId));
});

app.MapGet("/api/v1/islamic-finance/shariah-reviews/{id:long}", (long id, IShariahReviewService shariahReviewService) =>
{
    var entry = shariahReviewService.GetReviewCase(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapPost("/api/v1/islamic-finance/shariah-reviews", (
    CreateIslamicFinanceShariahReviewRequest request,
    IShariahReviewService shariahReviewService) =>
{
    return Results.Ok(shariahReviewService.CreateReviewCase(request));
});

app.MapPost("/api/v1/islamic-finance/shariah-reviews/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IShariahReviewService shariahReviewService) =>
{
    return Results.Ok(shariahReviewService.SubmitReviewCase(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/shariah-reviews/{id:long}/recommend-outcome", (
    long id,
    ClaimsPrincipal user,
    RecommendIslamicFinanceShariahOutcomeRequest request,
    IShariahReviewService shariahReviewService) =>
{
    return Results.Ok(shariahReviewService.RecommendOutcome(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/shariah-reviews/{id:long}/approve-outcome", (
    long id,
    ClaimsPrincipal user,
    IShariahReviewService shariahReviewService) =>
{
    return Results.Ok(shariahReviewService.ApproveOutcome(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases", (
    string? statusCode,
    long? financingRequestId,
    long? partnerLenderId,
    IMurabahaCaseService murabahaCaseService) =>
{
    return Results.Ok(murabahaCaseService.GetCases(statusCode, financingRequestId, partnerLenderId));
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases/{id:long}", (long id, IMurabahaCaseService murabahaCaseService) =>
{
    var entry = murabahaCaseService.GetCase(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases/{id:long}/history", (long id, IMurabahaCaseService murabahaCaseService) =>
{
    return Results.Ok(murabahaCaseService.GetCaseHistory(id));
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases/{id:long}/audit", (long id, IMurabahaCaseService murabahaCaseService) =>
{
    var audit = murabahaCaseService.GetCaseAudit(id);
    return audit is null ? Results.NotFound() : Results.Ok(audit);
});

app.MapPost("/api/v1/islamic-finance/murabaha-cases", (
    CreateIslamicFinanceMurabahaCaseRequest request,
    IMurabahaCaseService murabahaCaseService) =>
{
    return Results.Ok(murabahaCaseService.CreateCase(request));
});

app.MapPost("/api/v1/islamic-finance/murabaha-cases/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IMurabahaCaseService murabahaCaseService) =>
{
    return Results.Ok(murabahaCaseService.SubmitCase(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/murabaha-cases/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IMurabahaCaseService murabahaCaseService) =>
{
    return Results.Ok(murabahaCaseService.ApproveCase(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/murabaha-cases/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    IMurabahaCaseService murabahaCaseService) =>
{
    return Results.Ok(murabahaCaseService.ActivateCase(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/receivables-cases", (
    string? statusCode,
    long? customerPartyId,
    long? partnerLenderId,
    IReceivablesFinanceService receivablesFinanceService) =>
{
    return Results.Ok(receivablesFinanceService.GetCases(statusCode, customerPartyId, partnerLenderId));
});

app.MapGet("/api/v1/islamic-finance/receivables-cases/{id:long}", (
    long id,
    IReceivablesFinanceService receivablesFinanceService) =>
{
    var entry = receivablesFinanceService.GetCase(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapGet("/api/v1/islamic-finance/receivables-cases/{id:long}/history", (
    long id,
    IReceivablesFinanceService receivablesFinanceService) =>
{
    return Results.Ok(receivablesFinanceService.GetCaseHistory(id));
});

app.MapGet("/api/v1/islamic-finance/receivables-cases/{id:long}/audit", (
    long id,
    IReceivablesFinanceService receivablesFinanceService) =>
{
    var audit = receivablesFinanceService.GetCaseAudit(id);
    return audit is null ? Results.NotFound() : Results.Ok(audit);
});

app.MapPost("/api/v1/islamic-finance/receivables-cases", (
    CreateIslamicFinanceReceivablesCaseRequest request,
    IReceivablesFinanceService receivablesFinanceService) =>
{
    return Results.Ok(receivablesFinanceService.CreateCase(request));
});

app.MapPost("/api/v1/islamic-finance/receivables-cases/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IReceivablesFinanceService receivablesFinanceService) =>
{
    return Results.Ok(receivablesFinanceService.SubmitCase(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/receivables-cases/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IReceivablesFinanceService receivablesFinanceService) =>
{
    return Results.Ok(receivablesFinanceService.ApproveCase(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/receivables-cases/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    IReceivablesFinanceService receivablesFinanceService) =>
{
    return Results.Ok(receivablesFinanceService.ActivateCase(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/disbursements", (
    long? murabahaCaseId,
    string? statusCode,
    string? targetType,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    return Results.Ok(disbursementService.GetDisbursements(murabahaCaseId, statusCode, targetType));
});

app.MapGet("/api/v1/islamic-finance/disbursements/{id:long}", (
    long id,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    var entry = disbursementService.GetDisbursement(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapGet("/api/v1/islamic-finance/disbursements/{id:long}/history", (
    long id,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    return Results.Ok(disbursementService.GetDisbursementHistory(id));
});

app.MapGet("/api/v1/islamic-finance/disbursements/{id:long}/audit", (
    long id,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    var audit = disbursementService.GetDisbursementAudit(id);
    return audit is null ? Results.NotFound() : Results.Ok(audit);
});

app.MapPost("/api/v1/islamic-finance/disbursements", (
    CreateIslamicFinanceMurabahaDisbursementRequest request,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    return Results.Ok(disbursementService.CreateDisbursement(request));
});

app.MapPost("/api/v1/islamic-finance/disbursements/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    return Results.Ok(disbursementService.SubmitDisbursement(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/disbursements/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    return Results.Ok(disbursementService.ApproveDisbursement(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/disbursements/{id:long}/return", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    return Results.Ok(disbursementService.ReturnDisbursement(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/disbursements/{id:long}/reject", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    return Results.Ok(disbursementService.RejectDisbursement(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/disbursements/{id:long}/execute", (
    long id,
    ClaimsPrincipal user,
    ExecuteIslamicFinanceMurabahaDisbursementRequest request,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    return Results.Ok(disbursementService.ExecuteDisbursement(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/disbursements/{id:long}/suspend", (
    long id,
    ClaimsPrincipal user,
    SuspendIslamicFinanceMurabahaDisbursementRequest request,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    return Results.Ok(disbursementService.SuspendDisbursement(id, request, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/disbursements/{id:long}/close", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceMurabahaDisbursementService disbursementService) =>
{
    return Results.Ok(disbursementService.CloseDisbursement(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/settlements", (
    long? murabahaCaseId,
    string? statusCode,
    IIslamicFinanceSettlementService settlementService) =>
{
    return Results.Ok(settlementService.GetSettlements(murabahaCaseId, statusCode));
});

app.MapGet("/api/v1/islamic-finance/settlements/{id:long}", (
    long id,
    IIslamicFinanceSettlementService settlementService) =>
{
    var entry = settlementService.GetSettlement(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapGet("/api/v1/islamic-finance/settlements/{id:long}/history", (
    long id,
    IIslamicFinanceSettlementService settlementService) =>
{
    return Results.Ok(settlementService.GetSettlementHistory(id));
});

app.MapGet("/api/v1/islamic-finance/settlements/{id:long}/audit", (
    long id,
    IIslamicFinanceSettlementService settlementService) =>
{
    var audit = settlementService.GetSettlementAudit(id);
    return audit is null ? Results.NotFound() : Results.Ok(audit);
});

app.MapPost("/api/v1/islamic-finance/settlements", (
    CreateIslamicFinanceSettlementRequest request,
    IIslamicFinanceSettlementService settlementService) =>
{
    return Results.Ok(settlementService.CreateSettlement(request));
});

app.MapPost("/api/v1/islamic-finance/settlements/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceSettlementService settlementService) =>
{
    return Results.Ok(settlementService.SubmitSettlement(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/settlements/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceSettlementService settlementService) =>
{
    return Results.Ok(settlementService.ApproveSettlement(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/settlements/{id:long}/close", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceSettlementService settlementService) =>
{
    return Results.Ok(settlementService.CloseSettlement(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases/{id:long}/assets", (
    long id,
    IIslamicFinanceMurabahaAssetService murabahaAssetService) =>
{
    return Results.Ok(murabahaAssetService.GetAssets(id));
});

app.MapGet("/api/v1/islamic-finance/murabaha-assets/{assetId:long}", (
    long assetId,
    IIslamicFinanceMurabahaAssetService murabahaAssetService) =>
{
    var entry = murabahaAssetService.GetAsset(assetId);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapGet("/api/v1/islamic-finance/murabaha-assets/{assetId:long}/evidence", (
    long assetId,
    string? attachmentCategoryCode,
    IIslamicFinanceMurabahaAssetEvidenceService murabahaAssetEvidenceService) =>
{
    return Results.Ok(murabahaAssetEvidenceService.GetEvidence(assetId, attachmentCategoryCode));
});

app.MapGet("/api/v1/islamic-finance/murabaha-assets/{assetId:long}/evidence/{documentLinkId:long}", (
    long assetId,
    long documentLinkId,
    IIslamicFinanceMurabahaAssetEvidenceService murabahaAssetEvidenceService) =>
{
    var entry = murabahaAssetEvidenceService.GetEvidenceDocument(assetId, documentLinkId);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapPost("/api/v1/islamic-finance/murabaha-cases/{id:long}/assets", (
    long id,
    CreateIslamicFinanceMurabahaAssetRequest request,
    IIslamicFinanceMurabahaAssetService murabahaAssetService) =>
{
    return Results.Ok(murabahaAssetService.CreateAsset(id, request));
});

app.MapPost("/api/v1/islamic-finance/murabaha-assets/{assetId:long}/evidence", (
    long assetId,
    ClaimsPrincipal user,
    AttachIslamicFinanceMurabahaAssetEvidenceRequest request,
    IIslamicFinanceMurabahaAssetEvidenceService murabahaAssetEvidenceService) =>
{
    return Results.Ok(murabahaAssetEvidenceService.AttachEvidence(assetId, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases/{id:long}/contracts", (
    long id,
    IIslamicFinanceMurabahaContractService murabahaContractService) =>
{
    return Results.Ok(murabahaContractService.GetContracts(id));
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases/{id:long}/contracts/{documentLinkId:long}", (
    long id,
    long documentLinkId,
    IIslamicFinanceMurabahaContractService murabahaContractService) =>
{
    var entry = murabahaContractService.GetContract(id, documentLinkId);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapPost("/api/v1/islamic-finance/murabaha-cases/{id:long}/generate-contract", (
    long id,
    ClaimsPrincipal user,
    GenerateIslamicFinanceMurabahaContractRequest request,
    IIslamicFinanceMurabahaContractService murabahaContractService) =>
{
    return Results.Ok(murabahaContractService.GenerateContract(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases/{id:long}/accounting-hooks", (
    long id,
    string? postingStatusCode,
    IIslamicFinanceMurabahaAccountingHookService accountingHookService) =>
{
    return Results.Ok(accountingHookService.GetHooks(id, postingStatusCode));
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases/{id:long}/accounting-hooks/{accountingHookId:long}", (
    long id,
    long accountingHookId,
    IIslamicFinanceMurabahaAccountingHookService accountingHookService) =>
{
    var entry = accountingHookService.GetHook(id, accountingHookId);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapPost("/api/v1/islamic-finance/murabaha-cases/{id:long}/accounting-hooks/register", (
    long id,
    ClaimsPrincipal user,
    IIslamicFinanceMurabahaAccountingHookService accountingHookService) =>
{
    return Results.Ok(accountingHookService.RegisterHook(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/islamic-finance/murabaha-cases/{id:long}/accounting-hooks/{accountingHookId:long}/publish", (
    long id,
    long accountingHookId,
    ClaimsPrincipal user,
    IIslamicFinanceMurabahaAccountingHookService accountingHookService) =>
{
    return Results.Ok(accountingHookService.PublishHook(id, accountingHookId, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases/{id:long}/schedule", (
    long id,
    IMurabahaCaseService murabahaCaseService) =>
{
    var entry = murabahaCaseService.GetSchedule(id);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapPost("/api/v1/islamic-finance/murabaha-cases/{id:long}/generate-schedule", (
    long id,
    ClaimsPrincipal user,
    GenerateIslamicFinanceMurabahaScheduleRequest request,
    IMurabahaCaseService murabahaCaseService) =>
{
    return Results.Ok(murabahaCaseService.GenerateSchedule(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/islamic-finance/murabaha-cases/{id:long}/schedule/installments/{installmentNumber:int}", (
    long id,
    int installmentNumber,
    IMurabahaCaseService murabahaCaseService) =>
{
    var entry = murabahaCaseService.GetScheduleInstallment(id, installmentNumber);
    return entry is null ? Results.NotFound() : Results.Ok(entry);
});

app.MapGet("/api/v1/internal/work-queues/approvals", (string? moduleCode, IInternalWorkbenchService internalWorkbenchService) =>
{
    return Results.Ok(internalWorkbenchService.GetApprovalQueue(moduleCode));
});

app.MapGet("/api/v1/internal/work-queues/exceptions", (string? sourceType, IInternalWorkbenchService internalWorkbenchService) =>
{
    return Results.Ok(internalWorkbenchService.GetExceptionQueue(sourceType));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/quotations", (long partyId, IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetQuotations(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/rfq-invitations", (long partyId, IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetRfqInvitations(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/rfq-invitations/{rfqId:long}", (
    long partyId,
    long rfqId,
    IExternalPortalService externalPortalService) =>
{
    var rfq = externalPortalService.GetRfqInvitation(partyId, rfqId);
    return rfq is null ? Results.NotFound() : Results.Ok(rfq);
});

app.MapPost("/api/v1/external/parties/{partyId:long}/rfq-invitations/{rfqId:long}/respond", (
    long partyId,
    long rfqId,
    ClaimsPrincipal user,
    RespondExternalRfqInvitationRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.RespondToRfqInvitation(
        partyId,
        CurrentUserAccessor.GetRequiredUserId(user),
        rfqId,
        request));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/orders", (long partyId, IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetOrders(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/document-workflows", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetDocumentWorkflows(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/document-workflows/{workflowId:long}", (
    long partyId,
    long workflowId,
    IExternalPortalService externalPortalService) =>
{
    var workflow = externalPortalService.GetDocumentWorkflow(partyId, workflowId);
    return workflow is null ? Results.NotFound() : Results.Ok(workflow);
});

app.MapPost("/api/v1/external/parties/{partyId:long}/document-workflows", (
    long partyId,
    ClaimsPrincipal user,
    CreateExternalDocumentWorkflowRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.CreateDocumentWorkflow(
        partyId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/document-workflows/{workflowId:long}/submit", (
    long partyId,
    long workflowId,
    ClaimsPrincipal user,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.SubmitDocumentWorkflow(
        partyId,
        workflowId,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/document-workflows/{workflowId:long}/replace", (
    long partyId,
    long workflowId,
    ClaimsPrincipal user,
    ReplaceExternalDocumentWorkflowRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.ReplaceDocumentWorkflow(
        partyId,
        workflowId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/orders", (
    long partyId,
    CreateExternalCustomerOrderRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.CreateCustomerOrder(partyId, request));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/orders/{orderId:long}/submit", (
    long partyId,
    long orderId,
    ClaimsPrincipal user,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.SubmitCustomerOrder(
        partyId,
        orderId,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/purchase-orders", (long partyId, IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetPurchaseOrders(partyId));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/purchase-orders/{purchaseOrderId:long}/acknowledge", (
    long partyId,
    long purchaseOrderId,
    ClaimsPrincipal user,
    AcknowledgeExternalPurchaseOrderRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.AcknowledgePurchaseOrder(
        partyId,
        purchaseOrderId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/purchase-orders/{purchaseOrderId:long}/raise-issue", (
    long partyId,
    long purchaseOrderId,
    ClaimsPrincipal user,
    RaiseExternalPurchaseOrderIssueRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.RaisePurchaseOrderIssue(
        partyId,
        purchaseOrderId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/invoices", (long partyId, IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetInvoices(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/supplier-profile", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    var profile = externalPortalService.GetSupplierProfile(partyId);
    return profile is null ? Results.NotFound() : Results.Ok(profile);
});

app.MapPost("/api/v1/external/parties/{partyId:long}/supplier-profile", (
    long partyId,
    CreateSupplierProfileRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.CreateSupplierProfile(partyId, request));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/supplier-profile/submit", (
    long partyId,
    ClaimsPrincipal user,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.SubmitSupplierProfile(
        partyId,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/customer-profile", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    var profile = externalPortalService.GetCustomerProfile(partyId);
    return profile is null ? Results.NotFound() : Results.Ok(profile);
});

app.MapPost("/api/v1/external/parties/{partyId:long}/customer-profile", (
    long partyId,
    CreateCustomerProfileRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.CreateCustomerProfile(partyId, request));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/customer-profile/submit", (
    long partyId,
    ClaimsPrincipal user,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.SubmitCustomerProfile(
        partyId,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/quotations", (
    long partyId,
    ClaimsPrincipal user,
    CreateExternalSupplierQuotationRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.CreateQuotation(
        partyId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/quotations/{quotationId:long}", (
    long partyId,
    long quotationId,
    IExternalPortalService externalPortalService) =>
{
    var quotation = externalPortalService.GetQuotation(partyId, quotationId);
    return quotation is null ? Results.NotFound() : Results.Ok(quotation);
});

app.MapPost("/api/v1/external/parties/{partyId:long}/quotations/{quotationId:long}/submit", (
    long partyId,
    long quotationId,
    ClaimsPrincipal user,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.SubmitQuotation(
        partyId,
        quotationId,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/payments", (long partyId, IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetPayments(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/payments/{paymentId:long}/status", (
    long partyId,
    long paymentId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetCustomerPaymentStatus(partyId, paymentId));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/payments", (
    long partyId,
    CreateExternalCustomerPaymentRequest request,
    ClaimsPrincipal user,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.CreateCustomerPayment(
        partyId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/reports-statements/summary", (
    long partyId,
    DateOnly? dateFrom,
    DateOnly? dateTo,
    string? currencyCode,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetStatementSummary(partyId, dateFrom, dateTo, currencyCode));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/reports-statements/statement-lines", (
    long partyId,
    DateOnly? dateFrom,
    DateOnly? dateTo,
    string? currencyCode,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetStatementLines(partyId, dateFrom, dateTo, currencyCode));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/reports-statements", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetStatementDocuments(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/reports-statements/{statementId:long}", (
    long partyId,
    long statementId,
    IExternalPortalService externalPortalService) =>
{
    var statement = externalPortalService.GetStatementDetail(partyId, statementId);
    return statement is null ? Results.NotFound() : Results.Ok(statement);
});

app.MapGet("/api/v1/external/parties/{partyId:long}/reports-statements/{statementId:long}/delivery-logs", (
    long partyId,
    long statementId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetStatementDeliveryLogs(partyId, statementId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/customer-deliveries", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetCustomerDeliveries(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/customer-status-tracking", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetCustomerStatusTracking(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/service-requests", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetCustomerServiceRequests(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/accounting-office/requests", (
    long partyId,
    ClaimsPrincipal user,
    IAccountingOfficeClientRequestService accountingOfficeClientRequestService) =>
{
    CurrentUserAccessor.EnsureExternalPartyAccess(user, partyId);
    return Results.Ok(accountingOfficeClientRequestService.GetExternalPartyRequests(
        partyId,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/accounting-office/requests", (
    long partyId,
    ClaimsPrincipal user,
    CreateAccountingOfficeClientRequestRequest request,
    IAccountingOfficeClientRequestService accountingOfficeClientRequestService) =>
{
    CurrentUserAccessor.EnsureExternalPartyAccess(user, partyId);
    return Results.Ok(accountingOfficeClientRequestService.CreateExternalPartyRequest(
        partyId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/accounting-office/requests/{requestId:long}/documents/upload", async (
    long partyId,
    long requestId,
    HttpRequest request,
    ClaimsPrincipal user,
    IManagedComplianceDocumentUploadService managedComplianceDocumentUploadService,
    IDocumentStorageService documentStorageService,
    IAccountingOfficeClientRequestRepository accountingOfficeClientRequestRepository,
    CancellationToken cancellationToken) =>
{
    CurrentUserAccessor.EnsureExternalPartyAccess(user, partyId);

    var requestEntity = accountingOfficeClientRequestRepository.GetClientRequest(requestId);
    if (requestEntity is null || requestEntity.ClientPartyId != partyId)
    {
        return Results.NotFound();
    }

    var uploadRequest = await ReadComplianceUploadRequestAsync(request, cancellationToken);
    using var input = uploadRequest.File.OpenReadStream();
    var upload = await managedComplianceDocumentUploadService.UploadAsync(
        NormalizeUploadScope($"external-party-{partyId}-ao-request-{requestId}", uploadRequest.SubjectTypeCode),
        uploadRequest.DocumentType,
        uploadRequest.File.FileName,
        uploadRequest.File.ContentType,
        input,
        uploadRequest.File.Length,
        cancellationToken);

    return Results.Ok(documentStorageService.CreateDocument(CurrentUserAccessor.GetRequiredUserId(user), new CreateDocumentAttachmentRequest(
        ModuleCode: "ACCOUNTING_OFFICE",
        EntityName: "AO_CLIENT_REQUEST",
        EntityId: requestId,
        DocumentType: upload.DocumentType,
        AttachmentCategoryCode: "ACCOUNTING_NOTICE",
        FileName: upload.FileName,
        StorageReference: upload.StorageReference,
        StorageProviderCode: "MANAGED_UPLOAD",
        ContentType: upload.ContentType,
        FileSizeBytes: upload.FileSizeBytes,
        ChecksumText: null,
        RetentionUntilUtc: null)));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/service-requests", (
    long partyId,
    ClaimsPrincipal user,
    CreateExternalCustomerServiceRequestRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.CreateCustomerServiceRequest(
        partyId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/service-requests/{serviceRequestId:long}/submit", (
    long partyId,
    long serviceRequestId,
    ClaimsPrincipal user,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.SubmitCustomerServiceRequest(
        partyId,
        serviceRequestId,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/service-requests/{serviceRequestId:long}/escalate", (
    long partyId,
    long serviceRequestId,
    ClaimsPrincipal user,
    EscalateExternalCustomerServiceRequestRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.EscalateCustomerServiceRequest(
        partyId,
        serviceRequestId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/requests", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetFinancingRequests(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/products", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetFinancingProducts(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/requests/{financingRequestId:long}", (
    long partyId,
    long financingRequestId,
    IExternalPortalService externalPortalService) =>
{
    var request = externalPortalService.GetFinancingRequest(partyId, financingRequestId);
    return request is null ? Results.NotFound() : Results.Ok(request);
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/requests/{financingRequestId:long}/offers", (
    long partyId,
    long financingRequestId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetFinancingOffersForRequest(partyId, financingRequestId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/requests/{financingRequestId:long}/journey-summary", (
    long partyId,
    long financingRequestId,
    IExternalPortalService externalPortalService) =>
{
    var summary = externalPortalService.GetFinancingJourneySummary(partyId, financingRequestId);
    return summary is null ? Results.NotFound() : Results.Ok(summary);
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/requests/{financingRequestId:long}/notifications", (
    long partyId,
    long financingRequestId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetFinancingNotifications(partyId, financingRequestId));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/financing/requests", (
    long partyId,
    CreateExternalFinancingApplicationRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.CreateFinancingRequest(partyId, request));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/financing/requests/{financingRequestId:long}/submit", (
    long partyId,
    long financingRequestId,
    ClaimsPrincipal user,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.SubmitFinancingRequest(
        partyId,
        financingRequestId,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/offers", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetFinancingOffers(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/tasks", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetFinancingTasks(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/product-families", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetFinancingProductFamilies(partyId));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/financing/requests/{financingRequestId:long}/accept-offer", (
    long partyId,
    long financingRequestId,
    ClaimsPrincipal user,
    AcceptExternalFinancingOfferRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.AcceptFinancingOffer(
        partyId,
        financingRequestId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/murabaha-cases", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetMurabahaCases(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/murabaha-cases/{murabahaCaseId:long}", (
    long partyId,
    long murabahaCaseId,
    IExternalPortalService externalPortalService) =>
{
    var item = externalPortalService.GetMurabahaCase(partyId, murabahaCaseId);
    return item is null ? Results.NotFound() : Results.Ok(item);
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/receivables-cases", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetReceivablesCases(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/receivables-cases/{receivablesCaseId:long}", (
    long partyId,
    long receivablesCaseId,
    IExternalPortalService externalPortalService) =>
{
    var item = externalPortalService.GetReceivablesCase(partyId, receivablesCaseId);
    return item is null ? Results.NotFound() : Results.Ok(item);
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/disbursements", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetMurabahaDisbursements(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/disbursements/{disbursementId:long}", (
    long partyId,
    long disbursementId,
    IExternalPortalService externalPortalService) =>
{
    var item = externalPortalService.GetMurabahaDisbursement(partyId, disbursementId);
    return item is null ? Results.NotFound() : Results.Ok(item);
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/settlements", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetSettlements(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/financing/settlements/{settlementId:long}", (
    long partyId,
    long settlementId,
    IExternalPortalService externalPortalService) =>
{
    var item = externalPortalService.GetSettlement(partyId, settlementId);
    return item is null ? Results.NotFound() : Results.Ok(item);
});

app.MapPost("/api/v1/external/parties/{partyId:long}/pricing/evaluate", (
    long partyId,
    ExternalPricingEvaluationRequest request,
    IPricingRuleService pricingRuleService) =>
{
    return Results.Ok(pricingRuleService.EvaluatePricing(new PricingEvaluationRequest(
        request.BranchId,
        partyId,
        request.PricingDate,
        request.CurrencyCode,
        request.Lines.Select(line => new PricingEvaluationLineRequest(
            line.ItemId,
            line.OrderedQuantity,
            line.UnitOfMeasureCode,
            line.RequestedUnitPrice)).ToArray())));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/compliance-documents", (long partyId, IPartyOnboardingService partyOnboardingService) =>
{
    return Results.Ok(partyOnboardingService.GetComplianceDocuments(partyId));
});

app.MapGet("/api/v1/external/parties/{partyId:long}/customer-documents", (
    long partyId,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.GetCustomerDocuments(partyId));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/compliance-documents", (
    long partyId,
    ClaimsPrincipal user,
    RecordBusinessPartyComplianceDocumentRequest request,
    IPartyOnboardingService partyOnboardingService) =>
{
    return Results.Ok(partyOnboardingService.RecordComplianceDocument(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        request));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/compliance-documents/upload", async (
    long partyId,
    HttpRequest request,
    ClaimsPrincipal user,
    IManagedComplianceDocumentUploadService managedComplianceDocumentUploadService,
    IPartyOnboardingService partyOnboardingService,
    CancellationToken cancellationToken) =>
{
    CurrentUserAccessor.EnsureExternalPartyAccess(user, partyId);

    var uploadRequest = await ReadComplianceUploadRequestAsync(request, cancellationToken);
    using var input = uploadRequest.File.OpenReadStream();
    var upload = await managedComplianceDocumentUploadService.UploadAsync(
        $"external-party-{partyId}",
        uploadRequest.DocumentType,
        uploadRequest.File.FileName,
        uploadRequest.File.ContentType,
        input,
        uploadRequest.File.Length,
        cancellationToken);

    return Results.Ok(partyOnboardingService.RecordComplianceDocument(
        CurrentUserAccessor.GetRequiredUserId(user),
        partyId,
        new RecordBusinessPartyComplianceDocumentRequest(
            upload.DocumentType,
            upload.FileName,
            upload.StorageReference,
            upload.ContentType,
            upload.FileSizeBytes)));
});

app.MapPost("/api/v1/external/parties/{partyId:long}/customer-documents", (
    long partyId,
    ClaimsPrincipal user,
    RecordBusinessPartyComplianceDocumentRequest request,
    IExternalPortalService externalPortalService) =>
{
    return Results.Ok(externalPortalService.RecordCustomerDocument(
        partyId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapGet("/api/v1/procurement/purchase-requisitions", (IPurchaseRequisitionService purchaseRequisitionService) =>
{
    return Results.Ok(purchaseRequisitionService.GetPurchaseRequisitions());
});

app.MapGet("/api/v1/procurement/purchase-requisitions/{id:long}", (long id, IPurchaseRequisitionService purchaseRequisitionService) =>
{
    var requisition = purchaseRequisitionService.GetPurchaseRequisition(id);
    return requisition is null ? Results.NotFound() : Results.Ok(requisition);
});

app.MapPost("/api/v1/procurement/purchase-requisitions", (
    CreatePurchaseRequisitionRequest request,
    IPurchaseRequisitionService purchaseRequisitionService) =>
{
    return Results.Ok(purchaseRequisitionService.CreatePurchaseRequisition(request));
});

app.MapPost("/api/v1/procurement/purchase-requisitions/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IPurchaseRequisitionService purchaseRequisitionService) =>
{
    return Results.Ok(purchaseRequisitionService.SubmitPurchaseRequisition(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/procurement/rfqs", (IRfqService rfqService) =>
{
    return Results.Ok(rfqService.GetRfqs());
});

app.MapGet("/api/v1/procurement/rfqs/{id:long}", (long id, IRfqService rfqService) =>
{
    var rfq = rfqService.GetRfq(id);
    return rfq is null ? Results.NotFound() : Results.Ok(rfq);
});

app.MapPost("/api/v1/procurement/rfqs", (CreateRfqRequest request, IRfqService rfqService) =>
{
    return Results.Ok(rfqService.CreateRfq(request));
});

app.MapPost("/api/v1/procurement/rfqs/{id:long}/submit", (long id, ClaimsPrincipal user, IRfqService rfqService) =>
{
    return Results.Ok(rfqService.SubmitRfq(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/procurement/quotations", (long? rfqId, ISupplierQuotationService quotationService) =>
{
    return Results.Ok(quotationService.GetQuotations(rfqId));
});

app.MapGet("/api/v1/procurement/quotations/{id:long}", (long id, ISupplierQuotationService quotationService) =>
{
    var quotation = quotationService.GetQuotation(id);
    return quotation is null ? Results.NotFound() : Results.Ok(quotation);
});

app.MapPost("/api/v1/procurement/quotations", (CreateSupplierQuotationRequest request, ISupplierQuotationService quotationService) =>
{
    return Results.Ok(quotationService.CreateQuotation(request));
});

app.MapPost("/api/v1/procurement/quotations/{id:long}/submit", (long id, ClaimsPrincipal user, ISupplierQuotationService quotationService) =>
{
    return Results.Ok(quotationService.SubmitQuotation(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/procurement/evaluations", (long? rfqId, IRfqEvaluationService evaluationService) =>
{
    return Results.Ok(evaluationService.GetEvaluations(rfqId));
});

app.MapGet("/api/v1/procurement/evaluations/{id:long}", (long id, IRfqEvaluationService evaluationService) =>
{
    var evaluation = evaluationService.GetEvaluation(id);
    return evaluation is null ? Results.NotFound() : Results.Ok(evaluation);
});

app.MapPost("/api/v1/procurement/evaluations", (CreateRfqEvaluationRequest request, IRfqEvaluationService evaluationService) =>
{
    return Results.Ok(evaluationService.CreateEvaluation(request));
});

app.MapPost("/api/v1/procurement/evaluations/{id:long}/finalize", (long id, ClaimsPrincipal user, IRfqEvaluationService evaluationService) =>
{
    return Results.Ok(evaluationService.FinalizeRecommendation(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/procurement/evaluations/{id:long}/award", (long id, ClaimsPrincipal user, AwardPurchaseOrderRequest request, IRfqEvaluationService evaluationService) =>
{
    return Results.Ok(evaluationService.AwardPurchaseOrder(id, request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapGet("/api/v1/procurement/purchase-orders", (IPurchaseOrderService purchaseOrderService) =>
{
    return Results.Ok(purchaseOrderService.GetPurchaseOrders());
});

app.MapGet("/api/v1/procurement/purchase-orders/{id:long}", (long id, IPurchaseOrderService purchaseOrderService) =>
{
    var purchaseOrder = purchaseOrderService.GetPurchaseOrder(id);
    return purchaseOrder is null ? Results.NotFound() : Results.Ok(purchaseOrder);
});

app.MapGet("/api/v1/procurement/goods-receipts", (IGoodsReceiptService goodsReceiptService) =>
{
    return Results.Ok(goodsReceiptService.GetGoodsReceipts());
});

app.MapGet("/api/v1/procurement/goods-receipts/{id:long}", (long id, IGoodsReceiptService goodsReceiptService) =>
{
    var goodsReceipt = goodsReceiptService.GetGoodsReceipt(id);
    return goodsReceipt is null ? Results.NotFound() : Results.Ok(goodsReceipt);
});

app.MapPost("/api/v1/procurement/goods-receipts", (CreateGoodsReceiptRequest request, IGoodsReceiptService goodsReceiptService) =>
{
    return Results.Ok(goodsReceiptService.CreateGoodsReceipt(request));
});

app.MapPost("/api/v1/procurement/goods-receipts/{id:long}/post", (long id, ClaimsPrincipal user, IGoodsReceiptService goodsReceiptService) =>
{
    return Results.Ok(goodsReceiptService.PostGoodsReceipt(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/procurement/purchase-returns", (IPurchaseReturnService purchaseReturnService) =>
{
    return Results.Ok(purchaseReturnService.GetPurchaseReturns());
});

app.MapGet("/api/v1/procurement/purchase-returns/{id:long}", (long id, IPurchaseReturnService purchaseReturnService) =>
{
    var purchaseReturn = purchaseReturnService.GetPurchaseReturn(id);
    return purchaseReturn is null ? Results.NotFound() : Results.Ok(purchaseReturn);
});

app.MapPost("/api/v1/procurement/purchase-returns", (CreatePurchaseReturnRequest request, IPurchaseReturnService purchaseReturnService) =>
{
    return Results.Ok(purchaseReturnService.CreatePurchaseReturn(request));
});

app.MapPost("/api/v1/procurement/purchase-returns/{id:long}/submit", (long id, ClaimsPrincipal user, IPurchaseReturnService purchaseReturnService) =>
{
    return Results.Ok(purchaseReturnService.SubmitPurchaseReturn(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/procurement/purchase-returns/{id:long}/post", (long id, ClaimsPrincipal user, IPurchaseReturnService purchaseReturnService) =>
{
    return Results.Ok(purchaseReturnService.PostPurchaseReturn(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/procurement/purchase-returns/{id:long}/issue-debit-note", (long id, ClaimsPrincipal user, IssuePurchaseReturnDebitNoteRequest request, IPurchaseReturnService purchaseReturnService) =>
{
    return Results.Ok(purchaseReturnService.IssueDebitNote(id, request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapGet("/api/v1/procurement/ap-bills", (IAccountsPayableBillService accountsPayableBillService) =>
{
    return Results.Ok(accountsPayableBillService.GetBills());
});

app.MapGet("/api/v1/procurement/ap-bills/{id:long}", (long id, IAccountsPayableBillService accountsPayableBillService) =>
{
    var bill = accountsPayableBillService.GetBill(id);
    return bill is null ? Results.NotFound() : Results.Ok(bill);
});

app.MapPost("/api/v1/procurement/ap-bills", (CreateAccountsPayableBillRequest request, IAccountsPayableBillService accountsPayableBillService) =>
{
    return Results.Ok(accountsPayableBillService.CreateBill(request));
});

app.MapPost("/api/v1/procurement/ap-bills/{id:long}/submit", (long id, ClaimsPrincipal user, IAccountsPayableBillService accountsPayableBillService) =>
{
    return Results.Ok(accountsPayableBillService.SubmitBill(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/procurement/ap-bills/{id:long}/match", (long id, IAccountsPayableBillService accountsPayableBillService) =>
{
    return Results.Ok(accountsPayableBillService.GetBillMatch(id));
});

app.MapPost("/api/v1/procurement/ap-bills/{id:long}/hold", (
    long id,
    ClaimsPrincipal user,
    PlaceAccountsPayableBillOnHoldRequest request,
    IAccountsPayableBillService accountsPayableBillService) =>
{
    return Results.Ok(accountsPayableBillService.PlaceBillOnHold(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/procurement/ap-bills/{id:long}/resolve-dispute", (
    long id,
    ClaimsPrincipal user,
    ResolveAccountsPayableBillDisputeRequest request,
    IAccountsPayableBillService accountsPayableBillService) =>
{
    return Results.Ok(accountsPayableBillService.ResolveBillDispute(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/procurement/ap-bills/{id:long}/approve-match", (long id, ClaimsPrincipal user, IAccountsPayableBillService accountsPayableBillService) =>
{
    return Results.Ok(accountsPayableBillService.ApproveMatch(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/procurement/ap-bills/{id:long}/post", (long id, ClaimsPrincipal user, IAccountsPayableBillService accountsPayableBillService) =>
{
    return Results.Ok(accountsPayableBillService.PostBill(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/sales/orders", (ISalesOrderService salesOrderService) =>
{
    return Results.Ok(salesOrderService.GetSalesOrders());
});

app.MapGet("/api/v1/sales/pricing-rules", (bool? activeOnly, IPricingRuleService pricingRuleService) =>
{
    return Results.Ok(pricingRuleService.GetPricingRules(activeOnly ?? false));
});

app.MapGet("/api/v1/sales/pricing-rules/{id:long}", (long id, IPricingRuleService pricingRuleService) =>
{
    var rule = pricingRuleService.GetPricingRule(id);
    return rule is null ? Results.NotFound() : Results.Ok(rule);
});

app.MapPost("/api/v1/sales/pricing-rules", (CreatePricingRuleRequest request, IPricingRuleService pricingRuleService) =>
{
    return Results.Ok(pricingRuleService.CreatePricingRule(request));
});

app.MapPost("/api/v1/sales/pricing-rules/{id:long}/submit", (long id, ClaimsPrincipal user, IPricingRuleService pricingRuleService) =>
{
    return Results.Ok(pricingRuleService.SubmitPricingRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/sales/pricing-rules/{id:long}/approve", (long id, ClaimsPrincipal user, IPricingRuleService pricingRuleService) =>
{
    return Results.Ok(pricingRuleService.ApprovePricingRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/sales/pricing-rules/{id:long}/activate", (long id, ClaimsPrincipal user, IPricingRuleService pricingRuleService) =>
{
    return Results.Ok(pricingRuleService.ActivatePricingRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/sales/pricing-rules/evaluate", (PricingEvaluationRequest request, IPricingRuleService pricingRuleService) =>
{
    return Results.Ok(pricingRuleService.EvaluatePricing(request));
});

app.MapGet("/api/v1/sales/orders/{id:long}/discount-overrides", (long id, ISalesOrderService salesOrderService) =>
{
    return Results.Ok(salesOrderService.GetDiscountOverrides(id));
});

app.MapPost("/api/v1/sales/orders/{id:long}/discount-overrides", (long id, ClaimsPrincipal user, CreateSalesDiscountOverrideRequest request, ISalesOrderService salesOrderService) =>
{
    return Results.Ok(salesOrderService.CreateDiscountOverride(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/sales/orders/{id:long}/discount-overrides/{overrideId:long}/approve", (
    long id,
    long overrideId,
    ClaimsPrincipal user,
    ReviewSalesDiscountOverrideRequest request,
    ISalesOrderService salesOrderService) =>
{
    return Results.Ok(salesOrderService.ApproveDiscountOverride(id, CurrentUserAccessor.GetRequiredUserId(user), request, overrideId));
});

app.MapPost("/api/v1/sales/orders/{id:long}/discount-overrides/{overrideId:long}/reject", (
    long id,
    long overrideId,
    ClaimsPrincipal user,
    ReviewSalesDiscountOverrideRequest request,
    ISalesOrderService salesOrderService) =>
{
    return Results.Ok(salesOrderService.RejectDiscountOverride(id, CurrentUserAccessor.GetRequiredUserId(user), request, overrideId));
});

app.MapGet("/api/v1/sales/orders/{id:long}", (long id, ISalesOrderService salesOrderService) =>
{
    var salesOrder = salesOrderService.GetSalesOrder(id);
    return salesOrder is null ? Results.NotFound() : Results.Ok(salesOrder);
});

app.MapPost("/api/v1/sales/orders", (CreateSalesOrderRequest request, ISalesOrderService salesOrderService) =>
{
    return Results.Ok(salesOrderService.CreateSalesOrder(request));
});

app.MapPost("/api/v1/sales/orders/{id:long}/submit", (long id, ClaimsPrincipal user, ISalesOrderService salesOrderService) =>
{
    return Results.Ok(salesOrderService.SubmitSalesOrder(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/sales/customers/{customerId:long}/credit-control", (long customerId, string? currencyCode, DateOnly? asOfDate, ISalesOrderService salesOrderService) =>
{
    return Results.Ok(salesOrderService.GetCustomerCreditControl(customerId, currencyCode, asOfDate));
});

app.MapGet("/api/v1/sales/customers/{customerId:long}/receivables-finance-eligibility", (
    long customerId,
    string? currencyCode,
    DateOnly? asOfDate,
    IReceivablesFinanceService receivablesFinanceService) =>
{
    return Results.Ok(receivablesFinanceService.GetEligibleInvoices(customerId, currencyCode, asOfDate));
});

app.MapPost("/api/v1/sales/orders/{id:long}/credit-release", (long id, ClaimsPrincipal user, ReleaseSalesOrderCreditHoldRequest request, ISalesOrderService salesOrderService) =>
{
    return Results.Ok(salesOrderService.ReleaseCreditHold(id, request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapGet("/api/v1/sales/returns", (ISalesReturnService salesReturnService) =>
{
    return Results.Ok(salesReturnService.GetSalesReturns());
});

app.MapGet("/api/v1/sales/returns/{id:long}", (long id, ISalesReturnService salesReturnService) =>
{
    var salesReturn = salesReturnService.GetSalesReturn(id);
    return salesReturn is null ? Results.NotFound() : Results.Ok(salesReturn);
});

app.MapPost("/api/v1/sales/returns", (CreateSalesReturnRequest request, ISalesReturnService salesReturnService) =>
{
    return Results.Ok(salesReturnService.CreateSalesReturn(request));
});

app.MapPost("/api/v1/sales/returns/{id:long}/submit", (long id, ClaimsPrincipal user, ISalesReturnService salesReturnService) =>
{
    return Results.Ok(salesReturnService.SubmitSalesReturn(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/sales/returns/{id:long}/post", (long id, ClaimsPrincipal user, ISalesReturnService salesReturnService) =>
{
    return Results.Ok(salesReturnService.PostSalesReturn(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/sales/returns/{id:long}/issue-credit-note", (long id, ClaimsPrincipal user, IssueSalesReturnCreditNoteRequest request, ISalesReturnService salesReturnService) =>
{
    return Results.Ok(salesReturnService.IssueCreditNote(id, request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapGet("/api/v1/sales/dispatches", (IDispatchOrderService dispatchOrderService) =>
{
    return Results.Ok(dispatchOrderService.GetDispatchOrders());
});

app.MapGet("/api/v1/sales/dispatches/{id:long}", (long id, IDispatchOrderService dispatchOrderService) =>
{
    var dispatchOrder = dispatchOrderService.GetDispatchOrder(id);
    return dispatchOrder is null ? Results.NotFound() : Results.Ok(dispatchOrder);
});

app.MapPost("/api/v1/sales/dispatches", (CreateDispatchOrderRequest request, IDispatchOrderService dispatchOrderService) =>
{
    return Results.Ok(dispatchOrderService.CreateDispatchOrder(request));
});

app.MapPost("/api/v1/sales/dispatches/{id:long}/post", (long id, ClaimsPrincipal user, PostDispatchOrderRequest request, IDispatchOrderService dispatchOrderService) =>
{
    return Results.Ok(dispatchOrderService.PostDispatchOrder(id, request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapPost("/api/v1/sales/dispatches/{id:long}/proof-of-delivery", (
    long id,
    ClaimsPrincipal user,
    RecordProofOfDeliveryRequest request,
    IDispatchOrderService dispatchOrderService) =>
{
    return Results.Ok(dispatchOrderService.RecordProofOfDelivery(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/sales/dispatches/{id:long}/delivery-exception", (
    long id,
    ClaimsPrincipal user,
    RecordDeliveryExceptionRequest request,
    IDispatchOrderService dispatchOrderService) =>
{
    return Results.Ok(dispatchOrderService.RecordDeliveryException(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/sales/dispatches/{id:long}/recover-failed-delivery", (
    long id,
    ClaimsPrincipal user,
    RecoverFailedDeliveryRequest request,
    IDispatchOrderService dispatchOrderService) =>
{
    return Results.Ok(dispatchOrderService.RecoverFailedDelivery(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/ar-invoices", (IAccountsReceivableInvoiceService accountsReceivableInvoiceService) =>
{
    return Results.Ok(accountsReceivableInvoiceService.GetInvoices());
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}", (long id, IAccountsReceivableInvoiceService accountsReceivableInvoiceService) =>
{
    var invoice = accountsReceivableInvoiceService.GetInvoice(id);
    return invoice is null ? Results.NotFound() : Results.Ok(invoice);
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/tax-summary", (long id, IStatutoryTaxService statutoryTaxService) =>
{
    var summary = statutoryTaxService.GetAccountsReceivableInvoiceTaxSummary(id);
    return summary is null ? Results.NotFound() : Results.Ok(summary);
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/vat-breakdown-export", (long id, bool? download, IStatutoryTaxService statutoryTaxService) =>
{
    var export = statutoryTaxService.GetAccountsReceivableInvoiceVatBreakdownExport(id);
    return export is null
        ? Results.NotFound()
        : (download ?? false)
            ? ExportFileResultFactory.FromText(export.ContentText, export.ContentType, export.FileName)
            : Results.Ok(export);
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/withholding-summary", (long id, IStatutoryTaxService statutoryTaxService) =>
{
    var summary = statutoryTaxService.GetAccountsReceivableInvoiceWithholdingSummary(id);
    return summary is null ? Results.NotFound() : Results.Ok(summary);
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/withholding-export", (long id, bool? download, IStatutoryTaxService statutoryTaxService) =>
{
    var export = statutoryTaxService.GetAccountsReceivableInvoiceWithholdingExport(id);
    return export is null
        ? Results.NotFound()
        : (download ?? false)
            ? ExportFileResultFactory.FromText(export.ContentText, export.ContentType, export.FileName)
            : Results.Ok(export);
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/statutory-evidence-export", (long id, bool? download, IStatutoryTaxService statutoryTaxService) =>
{
    var export = statutoryTaxService.GetAccountsReceivableInvoiceStatutoryEvidenceExport(id);
    return export is null
        ? Results.NotFound()
        : (download ?? false)
            ? ExportFileResultFactory.FromText(export.ContentText, export.ContentType, export.FileName)
            : Results.Ok(export);
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/finance-review-package", (long id, IStatutoryTaxService statutoryTaxService) =>
{
    var package = statutoryTaxService.GetAccountsReceivableInvoiceFinanceReviewPackage(id);
    return package is null ? Results.NotFound() : ExportFileResultFactory.FromPackage(package);
});

app.MapPost("/api/v1/finance/ar-invoices", (CreateAccountsReceivableInvoiceRequest request, IAccountsReceivableInvoiceService accountsReceivableInvoiceService) =>
{
    return Results.Ok(accountsReceivableInvoiceService.CreateInvoice(request));
});

app.MapPost("/api/v1/finance/ar-invoices/{id:long}/submit", (long id, ClaimsPrincipal user, IAccountsReceivableInvoiceService accountsReceivableInvoiceService) =>
{
    return Results.Ok(accountsReceivableInvoiceService.SubmitInvoice(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/ar-invoices/{id:long}/approve", (long id, ClaimsPrincipal user, IAccountsReceivableInvoiceService accountsReceivableInvoiceService) =>
{
    return Results.Ok(accountsReceivableInvoiceService.ApproveInvoice(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/ar-invoices/{id:long}/post", (long id, ClaimsPrincipal user, IAccountsReceivableInvoiceService accountsReceivableInvoiceService) =>
{
    return Results.Ok(accountsReceivableInvoiceService.PostInvoice(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/ar-receipts", (IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.GetReceipts());
});

app.MapGet("/api/v1/finance/ar-receipts/{id:long}", (long id, IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    var receipt = accountsReceivableReceiptService.GetReceipt(id);
    return receipt is null ? Results.NotFound() : Results.Ok(receipt);
});

app.MapPost("/api/v1/finance/ar-receipts", (CreateAccountsReceivableReceiptRequest request, IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.CreateReceipt(request));
});

app.MapPost("/api/v1/finance/ar-receipts/{id:long}/submit", (long id, ClaimsPrincipal user, IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.SubmitReceipt(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/ar-receipts/{id:long}/approve", (long id, ClaimsPrincipal user, IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.ApproveReceipt(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/ar-receipts/{id:long}/post", (long id, ClaimsPrincipal user, IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.PostReceipt(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/ar-receipts/{id:long}/reverse", (
    long id,
    ClaimsPrincipal user,
    ReverseAccountsReceivableReceiptRequest request,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.ReverseReceipt(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/finance/ar-receipts/{id:long}/reallocate", (
    long id,
    ClaimsPrincipal user,
    ReallocateAccountsReceivableReceiptRequest request,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.ReallocateReceipt(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/customer-refunds", (
    long? customerId,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.GetCustomerRefunds(customerId));
});

app.MapGet("/api/v1/finance/customer-refunds/{id:long}", (
    long id,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    var refund = accountsReceivableReceiptService.GetCustomerRefund(id);
    return refund is null ? Results.NotFound() : Results.Ok(refund);
});

app.MapPost("/api/v1/finance/customer-refunds", (
    CreateCustomerRefundRequest request,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.CreateCustomerRefund(request));
});

app.MapPost("/api/v1/finance/customer-refunds/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.SubmitCustomerRefund(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/customer-refunds/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.ApproveCustomerRefund(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/customer-refunds/{id:long}/return", (
    long id,
    ClaimsPrincipal user,
    ReviewCustomerRefundRequest request,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.ReturnCustomerRefund(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/finance/customer-refunds/{id:long}/reject", (
    long id,
    ClaimsPrincipal user,
    ReviewCustomerRefundRequest request,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.RejectCustomerRefund(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/finance/customer-refunds/{id:long}/post", (
    long id,
    ClaimsPrincipal user,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.PostCustomerRefund(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/customer-refunds/{id:long}/orchestration", (
    long id,
    IAccountsReceivableReceiptService accountsReceivableReceiptService) =>
{
    return Results.Ok(accountsReceivableReceiptService.GetCustomerRefundOrchestration(id));
});

app.MapGet("/api/v1/finance/customer-refunds/{id:long}/provider-executions", (
    long id,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.GetRefundExecutions(id));
});

app.MapGet("/api/v1/finance/customer-payments/{id:long}/provider-executions", (
    long id,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.GetCustomerCollectionExecutions(id));
});

app.MapGet("/api/v1/finance/customer-payments/{id:long}/provider-contract", (
    long id,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.GetCustomerCollectionProviderContract(id));
});

app.MapPost("/api/v1/finance/customer-payments/{id:long}/queue-provider-execution", (
    long id,
    ClaimsPrincipal user,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.QueueCustomerCollection(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/customer-refunds/{id:long}/queue-provider-execution", (
    long id,
    ClaimsPrincipal user,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.QueueCustomerRefund(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/payment-executions", (
    long? paymentChannelConfigurationId,
    string? statusCode,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.GetExecutions(paymentChannelConfigurationId, statusCode));
});

app.MapGet("/api/v1/finance/payment-executions/{id:long}", (
    long id,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    var execution = paymentGatewayExecutionService.GetExecution(id);
    return execution is null ? Results.NotFound() : Results.Ok(execution);
});

app.MapGet("/api/v1/finance/payment-executions/{id:long}/provider-status-contract", (
    long id,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.GetExecutionProviderStatusContract(id));
});

app.MapGet("/api/v1/finance/payment-executions/{id:long}/provider-cancel-contract", (
    long id,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.GetExecutionProviderCancelContract(id));
});

app.MapPost("/api/v1/finance/payment-executions/dispatch-batch", (
    DispatchPaymentGatewayExecutionBatchRequest request,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.DispatchPendingExecutions(request));
});

app.MapGet("/api/v1/finance/ap-payments", (IAccountsPayablePaymentService accountsPayablePaymentService) =>
{
    return Results.Ok(accountsPayablePaymentService.GetPayments());
});

app.MapGet("/api/v1/finance/ap-payments/{id:long}", (long id, IAccountsPayablePaymentService accountsPayablePaymentService) =>
{
    var payment = accountsPayablePaymentService.GetPayment(id);
    return payment is null ? Results.NotFound() : Results.Ok(payment);
});

app.MapPost("/api/v1/finance/ap-payments", (CreateAccountsPayablePaymentRequest request, IAccountsPayablePaymentService accountsPayablePaymentService) =>
{
    return Results.Ok(accountsPayablePaymentService.CreatePayment(request));
});

app.MapPost("/api/v1/finance/ap-payments/{id:long}/submit", (long id, ClaimsPrincipal user, IAccountsPayablePaymentService accountsPayablePaymentService) =>
{
    return Results.Ok(accountsPayablePaymentService.SubmitPayment(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/ap-payments/{id:long}/approve", (long id, ClaimsPrincipal user, IAccountsPayablePaymentService accountsPayablePaymentService) =>
{
    return Results.Ok(accountsPayablePaymentService.ApprovePayment(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/ap-payments/{id:long}/post", (long id, ClaimsPrincipal user, IAccountsPayablePaymentService accountsPayablePaymentService) =>
{
    return Results.Ok(accountsPayablePaymentService.PostPayment(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/ap-payments/{id:long}/reverse", (
    long id,
    ClaimsPrincipal user,
    ReverseAccountsPayablePaymentRequest request,
    IAccountsPayablePaymentService accountsPayablePaymentService) =>
{
    return Results.Ok(accountsPayablePaymentService.ReversePayment(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/finance/ap-payments/{id:long}/repost", (
    long id,
    ClaimsPrincipal user,
    RepostAccountsPayablePaymentRequest request,
    IAccountsPayablePaymentService accountsPayablePaymentService) =>
{
    return Results.Ok(accountsPayablePaymentService.RepostPayment(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/ap-payments/{id:long}/provider-executions", (
    long id,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.GetSupplierPayoutExecutions(id));
});

app.MapGet("/api/v1/finance/ap-payments/{id:long}/provider-contract", (
    long id,
    string? integrationProviderCode,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.GetSupplierPayoutProviderContract(id, integrationProviderCode));
});

app.MapPost("/api/v1/finance/ap-payments/{id:long}/queue-provider-execution", (
    long id,
    QueueSupplierPayoutExecutionRequest request,
    ClaimsPrincipal user,
    IPaymentGatewayExecutionService paymentGatewayExecutionService) =>
{
    return Results.Ok(paymentGatewayExecutionService.QueueSupplierPayout(
        id,
        request.IntegrationProviderCode,
        CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/bank-transfer-batches", (IBankTransferBatchService bankTransferBatchService) =>
{
    return Results.Ok(bankTransferBatchService.GetBatches());
});

app.MapGet("/api/v1/finance/bank-transfer-batches/{id:long}", (long id, IBankTransferBatchService bankTransferBatchService) =>
{
    var batch = bankTransferBatchService.GetBatch(id);
    return batch is null ? Results.NotFound() : Results.Ok(batch);
});

app.MapPost("/api/v1/finance/bank-transfer-batches", (CreateBankTransferBatchRequest request, IBankTransferBatchService bankTransferBatchService) =>
{
    return Results.Ok(bankTransferBatchService.CreateBatch(request));
});

app.MapPost("/api/v1/finance/bank-transfer-batches/{id:long}/submit", (long id, ClaimsPrincipal user, IBankTransferBatchService bankTransferBatchService) =>
{
    return Results.Ok(bankTransferBatchService.SubmitBatch(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/bank-transfer-batches/{id:long}/approve", (long id, ClaimsPrincipal user, IBankTransferBatchService bankTransferBatchService) =>
{
    return Results.Ok(bankTransferBatchService.ApproveBatch(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/bank-transfer-batches/{id:long}/post", (long id, ClaimsPrincipal user, IBankTransferBatchService bankTransferBatchService) =>
{
    return Results.Ok(bankTransferBatchService.PostBatch(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/payment-settlement-batches", (
    long? paymentChannelConfigurationId,
    IPaymentSettlementBatchService paymentSettlementBatchService) =>
{
    return Results.Ok(paymentSettlementBatchService.GetBatches(paymentChannelConfigurationId));
});

app.MapGet("/api/v1/finance/payment-settlement-batches/{id:long}", (long id, IPaymentSettlementBatchService paymentSettlementBatchService) =>
{
    var batch = paymentSettlementBatchService.GetBatch(id);
    return batch is null ? Results.NotFound() : Results.Ok(batch);
});

app.MapPost("/api/v1/finance/payment-settlement-batches", (
    CreatePaymentSettlementBatchRequest request,
    IPaymentSettlementBatchService paymentSettlementBatchService) =>
{
    return Results.Ok(paymentSettlementBatchService.CreateBatch(request));
});

app.MapPost("/api/v1/finance/payment-settlement-batches/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IPaymentSettlementBatchService paymentSettlementBatchService) =>
{
    return Results.Ok(paymentSettlementBatchService.SubmitBatch(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/payment-settlement-batches/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IPaymentSettlementBatchService paymentSettlementBatchService) =>
{
    return Results.Ok(paymentSettlementBatchService.ApproveBatch(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/payment-settlement-batches/{id:long}/post", (
    long id,
    ClaimsPrincipal user,
    IPaymentSettlementBatchService paymentSettlementBatchService) =>
{
    return Results.Ok(paymentSettlementBatchService.PostBatch(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/payment-settlement-exceptions", (
    long? paymentSettlementBatchId,
    string? statusCode,
    IPaymentSettlementBatchService paymentSettlementBatchService) =>
{
    return Results.Ok(paymentSettlementBatchService.GetExceptions(paymentSettlementBatchId, statusCode));
});

app.MapGet("/api/v1/finance/payment-settlement-exceptions/{id:long}", (
    long id,
    IPaymentSettlementBatchService paymentSettlementBatchService) =>
{
    var exception = paymentSettlementBatchService.GetException(id);
    return exception is null ? Results.NotFound() : Results.Ok(exception);
});

app.MapPost("/api/v1/finance/payment-settlement-exceptions/{id:long}/confirm", (
    long id,
    ClaimsPrincipal user,
    ResolvePaymentSettlementExceptionRequest request,
    IPaymentSettlementBatchService paymentSettlementBatchService) =>
{
    return Results.Ok(paymentSettlementBatchService.ConfirmException(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/finance/payment-settlement-exceptions/{id:long}/override", (
    long id,
    ClaimsPrincipal user,
    ResolvePaymentSettlementExceptionRequest request,
    IPaymentSettlementBatchService paymentSettlementBatchService) =>
{
    return Results.Ok(paymentSettlementBatchService.OverrideException(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/cash-accounts", (ICashAccountService cashAccountService) =>
{
    return Results.Ok(cashAccountService.GetCashAccounts());
});

app.MapGet("/api/v1/finance/cash-accounts/{id:long}", (long id, ICashAccountService cashAccountService) =>
{
    var account = cashAccountService.GetCashAccount(id);
    return account is null ? Results.NotFound() : Results.Ok(account);
});

app.MapPost("/api/v1/finance/cash-accounts", (CreateCashAccountRequest request, ICashAccountService cashAccountService) =>
{
    return Results.Ok(cashAccountService.CreateCashAccount(request));
});

app.MapGet("/api/v1/finance/fx-quotes", (
    string? currencyCode,
    string? baseCurrencyCode,
    long? integrationEndpointId,
    DateOnly? dateFrom,
    DateOnly? dateTo,
    IForeignExchangeQuoteService foreignExchangeQuoteService) =>
{
    return Results.Ok(foreignExchangeQuoteService.GetForeignExchangeQuotes(currencyCode, baseCurrencyCode, integrationEndpointId, dateFrom, dateTo));
});

app.MapGet("/api/v1/finance/fx-quotes/latest", (
    string currencyCode,
    string? baseCurrencyCode,
    DateOnly? asOfDate,
    long? integrationEndpointId,
    IForeignExchangeQuoteService foreignExchangeQuoteService) =>
{
    var quote = foreignExchangeQuoteService.GetLatestForeignExchangeQuote(currencyCode, baseCurrencyCode, asOfDate, integrationEndpointId);
    return quote is null ? Results.NotFound() : Results.Ok(quote);
});

app.MapPost("/api/v1/finance/fx-quotes/ingest", (
    ClaimsPrincipal user,
    IngestForeignExchangeQuotesRequest request,
    IForeignExchangeQuoteService foreignExchangeQuoteService) =>
{
    return Results.Ok(foreignExchangeQuoteService.IngestQuotes(CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/fx-overrides", (
    string? currencyCode,
    string? baseCurrencyCode,
    string? statusCode,
    DateOnly? effectiveDateFrom,
    DateOnly? effectiveDateTo,
    IForeignExchangeOverrideService foreignExchangeOverrideService) =>
{
    return Results.Ok(foreignExchangeOverrideService.GetForeignExchangeOverrides(currencyCode, baseCurrencyCode, statusCode, effectiveDateFrom, effectiveDateTo));
});

app.MapGet("/api/v1/finance/fx-overrides/{id:long}", (long id, IForeignExchangeOverrideService foreignExchangeOverrideService) =>
{
    var overrideEntry = foreignExchangeOverrideService.GetForeignExchangeOverride(id);
    return overrideEntry is null ? Results.NotFound() : Results.Ok(overrideEntry);
});

app.MapPost("/api/v1/finance/fx-overrides", (
    CreateForeignExchangeOverrideRequest request,
    IForeignExchangeOverrideService foreignExchangeOverrideService) =>
{
    return Results.Ok(foreignExchangeOverrideService.CreateForeignExchangeOverride(request));
});

app.MapPost("/api/v1/finance/fx-overrides/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IForeignExchangeOverrideService foreignExchangeOverrideService) =>
{
    return Results.Ok(foreignExchangeOverrideService.SubmitForeignExchangeOverride(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/fx-overrides/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IForeignExchangeOverrideService foreignExchangeOverrideService) =>
{
    return Results.Ok(foreignExchangeOverrideService.ApproveForeignExchangeOverride(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/fx-revaluations", (IForeignExchangeRevaluationService foreignExchangeRevaluationService) =>
{
    return Results.Ok(foreignExchangeRevaluationService.GetForeignExchangeRevaluations());
});

app.MapGet("/api/v1/finance/fx-revaluations/{id:long}", (long id, IForeignExchangeRevaluationService foreignExchangeRevaluationService) =>
{
    var revaluation = foreignExchangeRevaluationService.GetForeignExchangeRevaluation(id);
    return revaluation is null ? Results.NotFound() : Results.Ok(revaluation);
});

app.MapPost("/api/v1/finance/fx-revaluations", (
    CreateForeignExchangeRevaluationRequest request,
    IForeignExchangeRevaluationService foreignExchangeRevaluationService) =>
{
    return Results.Ok(foreignExchangeRevaluationService.CreateForeignExchangeRevaluation(request));
});

app.MapPost("/api/v1/finance/fx-revaluations/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IForeignExchangeRevaluationService foreignExchangeRevaluationService) =>
{
    return Results.Ok(foreignExchangeRevaluationService.SubmitForeignExchangeRevaluation(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/fx-revaluations/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IForeignExchangeRevaluationService foreignExchangeRevaluationService) =>
{
    return Results.Ok(foreignExchangeRevaluationService.ApproveForeignExchangeRevaluation(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/fx-revaluations/{id:long}/post", (
    long id,
    ClaimsPrincipal user,
    IForeignExchangeRevaluationService foreignExchangeRevaluationService) =>
{
    return Results.Ok(foreignExchangeRevaluationService.PostForeignExchangeRevaluation(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/card-token-references", (
    bool? activeOnly,
    long? partyId,
    string? integrationProviderCode,
    string? usageCode,
    ICardTokenReferenceService cardTokenReferenceService) =>
{
    return Results.Ok(cardTokenReferenceService.GetCardTokenReferences(activeOnly ?? false, partyId, integrationProviderCode, usageCode));
});

app.MapGet("/api/v1/finance/card-token-references/{id:long}", (long id, ICardTokenReferenceService cardTokenReferenceService) =>
{
    var reference = cardTokenReferenceService.GetCardTokenReference(id);
    return reference is null ? Results.NotFound() : Results.Ok(reference);
});

app.MapPost("/api/v1/finance/card-token-references", (
    CreateCardTokenReferenceRequest request,
    ICardTokenReferenceService cardTokenReferenceService) =>
{
    return Results.Ok(cardTokenReferenceService.CreateCardTokenReference(request));
});

app.MapPost("/api/v1/finance/card-token-references/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    ICardTokenReferenceService cardTokenReferenceService) =>
{
    return Results.Ok(cardTokenReferenceService.SubmitCardTokenReference(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/card-token-references/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    ICardTokenReferenceService cardTokenReferenceService) =>
{
    return Results.Ok(cardTokenReferenceService.ApproveCardTokenReference(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/card-token-references/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    ICardTokenReferenceService cardTokenReferenceService) =>
{
    return Results.Ok(cardTokenReferenceService.ActivateCardTokenReference(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/card-token-references/{id:long}/suspend", (
    long id,
    ClaimsPrincipal user,
    SuspendCardTokenReferenceRequest request,
    ICardTokenReferenceService cardTokenReferenceService) =>
{
    return Results.Ok(cardTokenReferenceService.SuspendCardTokenReference(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/payment-channels", (
    bool? activeOnly,
    string? integrationProviderCode,
    string? channelTypeCode,
    string? usageCode,
    IPaymentChannelConfigurationService paymentChannelConfigurationService) =>
{
    return Results.Ok(paymentChannelConfigurationService.GetPaymentChannels(activeOnly ?? false, integrationProviderCode, channelTypeCode, usageCode));
});

app.MapGet("/api/v1/finance/payment-channels/{id:long}", (long id, IPaymentChannelConfigurationService paymentChannelConfigurationService) =>
{
    var channel = paymentChannelConfigurationService.GetPaymentChannel(id);
    return channel is null ? Results.NotFound() : Results.Ok(channel);
});

app.MapPost("/api/v1/finance/payment-channels", (
    CreatePaymentChannelConfigurationRequest request,
    IPaymentChannelConfigurationService paymentChannelConfigurationService) =>
{
    return Results.Ok(paymentChannelConfigurationService.CreatePaymentChannel(request));
});

app.MapPost("/api/v1/finance/payment-channels/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IPaymentChannelConfigurationService paymentChannelConfigurationService) =>
{
    return Results.Ok(paymentChannelConfigurationService.SubmitPaymentChannel(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/payment-channels/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IPaymentChannelConfigurationService paymentChannelConfigurationService) =>
{
    return Results.Ok(paymentChannelConfigurationService.ApprovePaymentChannel(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/payment-channels/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    IPaymentChannelConfigurationService paymentChannelConfigurationService) =>
{
    return Results.Ok(paymentChannelConfigurationService.ActivatePaymentChannel(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/payment-channels/{id:long}/callbacks", (
    long id,
    string? statusCode,
    IGatewayCallbackService gatewayCallbackService) =>
{
    return Results.Ok(gatewayCallbackService.GetCallbacks(id, statusCode));
});

app.MapGet("/api/v1/finance/payment-channels/{channelId:long}/callbacks/{inboxMessageId:long}", (
    long channelId,
    long inboxMessageId,
    IGatewayCallbackService gatewayCallbackService) =>
{
    var callback = gatewayCallbackService.GetCallback(channelId, inboxMessageId);
    return callback is null ? Results.NotFound() : Results.Ok(callback);
});

app.MapPost("/api/v1/finance/payment-channels/{channelId:long}/callbacks/{inboxMessageId:long}/replay", (
    long channelId,
    long inboxMessageId,
    ClaimsPrincipal user,
    ReplayDeadLetterQueueItemRequest request,
    IGatewayCallbackService gatewayCallbackService) =>
{
    return Results.Ok(gatewayCallbackService.ReplayCallback(
        channelId,
        inboxMessageId,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapPost("/api/v1/finance/payment-channels/{id:long}/callbacks/process-batch", (
    long id,
    ProcessGatewayCallbackBatchRequest request,
    IGatewayCallbackService gatewayCallbackService) =>
{
    return Results.Ok(gatewayCallbackService.ProcessCallbacks(id, request));
});

app.MapPost("/api/v1/payments/channels/{channelId:long}/callback", async (
    long channelId,
    HttpRequest httpRequest,
    IGatewayCallbackService gatewayCallbackService) =>
{
    using var reader = new StreamReader(httpRequest.Body);
    var payloadText = await reader.ReadToEndAsync();
    var result = gatewayCallbackService.Receive(new GatewayCallbackReceiveRequest(
        channelId,
        httpRequest.Headers["X-Callback-Signature"].ToString(),
        httpRequest.Headers["X-External-Message-Id"].ToString(),
        httpRequest.Headers["X-Correlation-Key"].ToString(),
        httpRequest.Headers["X-Message-Type"].ToString(),
        payloadText));

    return result.DecisionCode switch
    {
        "ACCEPTED" => Results.Ok(result),
        "REPLAY_BLOCKED" => Results.Conflict(result),
        "INVALID_SIGNATURE" => Results.Json(result, statusCode: StatusCodes.Status403Forbidden),
        _ => Results.BadRequest(result)
    };
});

app.MapGet("/api/v1/finance/wallet-rules", (
    bool? activeOnly,
    string? integrationProviderCode,
    string? transactionTypeCode,
    IWalletRuleService walletRuleService) =>
{
    return Results.Ok(walletRuleService.GetWalletRules(activeOnly ?? false, integrationProviderCode, transactionTypeCode));
});

app.MapGet("/api/v1/finance/wallet-rules/{id:long}", (long id, IWalletRuleService walletRuleService) =>
{
    var rule = walletRuleService.GetWalletRule(id);
    return rule is null ? Results.NotFound() : Results.Ok(rule);
});

app.MapPost("/api/v1/finance/wallet-rules", (
    CreateWalletRuleRequest request,
    IWalletRuleService walletRuleService) =>
{
    return Results.Ok(walletRuleService.CreateWalletRule(request));
});

app.MapPost("/api/v1/finance/wallet-rules/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    IWalletRuleService walletRuleService) =>
{
    return Results.Ok(walletRuleService.SubmitWalletRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/wallet-rules/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    IWalletRuleService walletRuleService) =>
{
    return Results.Ok(walletRuleService.ApproveWalletRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/wallet-rules/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    IWalletRuleService walletRuleService) =>
{
    return Results.Ok(walletRuleService.ActivateWalletRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/wallet-rules/evaluate", (
    WalletRuleEvaluationRequest request,
    IWalletRuleService walletRuleService) =>
{
    return Results.Ok(walletRuleService.EvaluateWalletRule(request));
});

app.MapGet("/api/v1/finance/treasury-transfers", (ITreasuryTransferService treasuryTransferService) =>
{
    return Results.Ok(treasuryTransferService.GetTreasuryTransfers());
});

app.MapGet("/api/v1/finance/treasury-transfers/{id:long}", (long id, ITreasuryTransferService treasuryTransferService) =>
{
    var transfer = treasuryTransferService.GetTreasuryTransfer(id);
    return transfer is null ? Results.NotFound() : Results.Ok(transfer);
});

app.MapPost("/api/v1/finance/treasury-transfers", (CreateTreasuryTransferRequest request, ITreasuryTransferService treasuryTransferService) =>
{
    return Results.Ok(treasuryTransferService.CreateTreasuryTransfer(request));
});

app.MapPost("/api/v1/finance/treasury-transfers/{id:long}/submit", (long id, ClaimsPrincipal user, ITreasuryTransferService treasuryTransferService) =>
{
    return Results.Ok(treasuryTransferService.SubmitTreasuryTransfer(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/treasury-transfers/{id:long}/approve", (long id, ClaimsPrincipal user, ITreasuryTransferService treasuryTransferService) =>
{
    return Results.Ok(treasuryTransferService.ApproveTreasuryTransfer(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/treasury-transfers/{id:long}/post", (long id, ClaimsPrincipal user, ITreasuryTransferService treasuryTransferService) =>
{
    return Results.Ok(treasuryTransferService.PostTreasuryTransfer(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/collections/workbench", (
    DateOnly? asOfDate,
    ICollectionsWorkbenchService collectionsWorkbenchService) =>
{
    return Results.Ok(collectionsWorkbenchService.GetSummary(asOfDate));
});

app.MapGet("/api/v1/finance/collections/queue", (
    DateOnly? asOfDate,
    long? customerId,
    string? currencyCode,
    bool actionRequiredOnly,
    ICollectionsWorkbenchService collectionsWorkbenchService) =>
{
    return Results.Ok(collectionsWorkbenchService.GetQueue(asOfDate, customerId, currencyCode, actionRequiredOnly));
});

app.MapGet("/api/v1/finance/collections/customers/{customerId:long}/summary", (
    long customerId,
    DateOnly? asOfDate,
    string? currencyCode,
    ICollectionsWorkbenchService collectionsWorkbenchService) =>
{
    return Results.Ok(collectionsWorkbenchService.GetCustomerSummary(customerId, asOfDate, currencyCode));
});

app.MapGet("/api/v1/finance/collections/invoices/{id:long}/follow-ups", (
    long id,
    ICollectionsWorkbenchService collectionsWorkbenchService) =>
{
    return Results.Ok(collectionsWorkbenchService.GetFollowUpActions(id));
});

app.MapPost("/api/v1/finance/collections/invoices/{id:long}/follow-up", (
    long id,
    ClaimsPrincipal user,
    RecordCollectionsFollowUpRequest request,
    ICollectionsWorkbenchService collectionsWorkbenchService) =>
{
    return Results.Ok(collectionsWorkbenchService.RecordFollowUp(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/customer-statements", (
    long? customerId,
    ICustomerStatementService customerStatementService) =>
{
    return Results.Ok(customerStatementService.GetStatements(customerId));
});

app.MapGet("/api/v1/finance/customer-statements/{id:long}", (
    long id,
    ICustomerStatementService customerStatementService) =>
{
    var statement = customerStatementService.GetStatement(id);
    return statement is null ? Results.NotFound() : Results.Ok(statement);
});

app.MapPost("/api/v1/finance/customer-statements", (
    ClaimsPrincipal user,
    CreateCustomerStatementRequest request,
    ICustomerStatementService customerStatementService) =>
{
    return Results.Ok(customerStatementService.GenerateStatement(CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/customer-statements/{id:long}/delivery-logs", (
    long id,
    ICustomerStatementService customerStatementService) =>
{
    return Results.Ok(customerStatementService.GetDeliveryLogs(id));
});

app.MapPost("/api/v1/finance/customer-statements/{id:long}/delivery-logs", (
    long id,
    ClaimsPrincipal user,
    RecordCustomerStatementDeliveryRequest request,
    ICustomerStatementService customerStatementService) =>
{
    return Results.Ok(customerStatementService.RecordDelivery(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/supplier-statements", (
    long? supplierId,
    ISupplierStatementService supplierStatementService) =>
{
    return Results.Ok(supplierStatementService.GetStatements(supplierId));
});

app.MapGet("/api/v1/finance/supplier-statements/{id:long}", (
    long id,
    ISupplierStatementService supplierStatementService) =>
{
    var statement = supplierStatementService.GetStatement(id);
    return statement is null ? Results.NotFound() : Results.Ok(statement);
});

app.MapPost("/api/v1/finance/supplier-statements", (
    ClaimsPrincipal user,
    CreateSupplierStatementRequest request,
    ISupplierStatementService supplierStatementService) =>
{
    return Results.Ok(supplierStatementService.GenerateStatement(CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/supplier-statements/{id:long}/delivery-logs", (
    long id,
    ISupplierStatementService supplierStatementService) =>
{
    return Results.Ok(supplierStatementService.GetDeliveryLogs(id));
});

app.MapPost("/api/v1/finance/supplier-statements/{id:long}/delivery-logs", (
    long id,
    ClaimsPrincipal user,
    RecordSupplierStatementDeliveryRequest request,
    ISupplierStatementService supplierStatementService) =>
{
    return Results.Ok(supplierStatementService.RecordDelivery(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/finance/supplier-statement-delivery-logs/{id:long}/acknowledge", (
    long id,
    ClaimsPrincipal user,
    AcknowledgeSupplierStatementDeliveryRequest request,
    ISupplierStatementService supplierStatementService) =>
{
    return Results.Ok(supplierStatementService.AcknowledgeDelivery(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/finance/supplier-account-reconciliations", (
    DateOnly? asOfDate,
    long? supplierId,
    string? currencyCode,
    ISupplierAccountReconciliationService supplierAccountReconciliationService) =>
{
    return Results.Ok(supplierAccountReconciliationService.GetSummaries(asOfDate, supplierId, currencyCode));
});

app.MapGet("/api/v1/finance/supplier-account-reconciliations/{supplierId:long}", (
    long supplierId,
    DateOnly? asOfDate,
    string? currencyCode,
    ISupplierAccountReconciliationService supplierAccountReconciliationService) =>
{
    return Results.Ok(supplierAccountReconciliationService.GetDetail(supplierId, asOfDate, currencyCode));
});

app.MapGet("/api/v1/finance/accounting-periods", (IAccountingPeriodService accountingPeriodService) =>
{
    return Results.Ok(accountingPeriodService.GetPeriods());
});

app.MapGet("/api/v1/finance/accounting-periods/{id:long}/close-readiness", (long id, IAccountingPeriodService accountingPeriodService) =>
{
    return Results.Ok(accountingPeriodService.GetCloseReadiness(id));
});

app.MapGet("/api/v1/finance/accounting-periods/{id:long}/month-end-review", (long id, IAccountingPeriodService accountingPeriodService) =>
{
    return Results.Ok(accountingPeriodService.GetMonthEndReview(id));
});

app.MapGet("/api/v1/finance/close-journals", (IFinanceCloseJournalService financeCloseJournalService) =>
{
    return Results.Ok(financeCloseJournalService.GetCloseJournals());
});

app.MapGet("/api/v1/finance/close-journals/{id:long}", (long id, IFinanceCloseJournalService financeCloseJournalService) =>
{
    var journal = financeCloseJournalService.GetCloseJournal(id);
    return journal is null ? Results.NotFound() : Results.Ok(journal);
});

app.MapPost("/api/v1/finance/close-journals", (CreateFinanceCloseJournalRequest request, IFinanceCloseJournalService financeCloseJournalService) =>
{
    return Results.Ok(financeCloseJournalService.CreateCloseJournal(request));
});

app.MapPost("/api/v1/finance/close-journals/{id:long}/submit", (long id, ClaimsPrincipal user, IFinanceCloseJournalService financeCloseJournalService) =>
{
    return Results.Ok(financeCloseJournalService.SubmitCloseJournal(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/close-journals/{id:long}/approve", (long id, ClaimsPrincipal user, IFinanceCloseJournalService financeCloseJournalService) =>
{
    return Results.Ok(financeCloseJournalService.ApproveCloseJournal(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/close-journals/{id:long}/post", (long id, ClaimsPrincipal user, IFinanceCloseJournalService financeCloseJournalService) =>
{
    return Results.Ok(financeCloseJournalService.PostCloseJournal(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/accounting-periods/{id:long}/mark-ready-to-close", (long id, ClaimsPrincipal user, IAccountingPeriodService accountingPeriodService) =>
{
    return Results.Ok(accountingPeriodService.MarkReadyToClose(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/accounting-periods/{id:long}/close", (long id, ClaimsPrincipal user, IAccountingPeriodService accountingPeriodService) =>
{
    return Results.Ok(accountingPeriodService.Close(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/finance/bank-statements", (IReconciliationService reconciliationService) =>
{
    return Results.Ok(reconciliationService.GetBankStatements());
});

app.MapGet("/api/v1/finance/bank-statements/{id:long}", (long id, IReconciliationService reconciliationService) =>
{
    var statement = reconciliationService.GetBankStatement(id);
    return statement is null ? Results.NotFound() : Results.Ok(statement);
});

app.MapPost("/api/v1/finance/bank-statements", (CreateBankStatementRequest request, IReconciliationService reconciliationService) =>
{
    return Results.Ok(reconciliationService.CreateBankStatement(request));
});

app.MapGet("/api/v1/finance/reconciliations", (IReconciliationService reconciliationService) =>
{
    return Results.Ok(reconciliationService.GetRuns());
});

app.MapGet("/api/v1/finance/reconciliations/{id:long}", (long id, IReconciliationService reconciliationService) =>
{
    var run = reconciliationService.GetRun(id);
    return run is null ? Results.NotFound() : Results.Ok(run);
});

app.MapGet("/api/v1/finance/reconciliations/exception-queue", (string? matchStatusCode, IReconciliationService reconciliationService) =>
{
    return Results.Ok(reconciliationService.GetExceptionQueue(matchStatusCode));
});

app.MapGet("/api/v1/finance/reconciliations/history", (
    long? receiptReconciliationRunId,
    long? bankStatementId,
    string? resolutionCode,
    string? matchedDocumentType,
    IReconciliationService reconciliationService) =>
{
    return Results.Ok(reconciliationService.GetHistory(receiptReconciliationRunId, bankStatementId, resolutionCode, matchedDocumentType));
});

app.MapGet("/api/v1/finance/reconciliations/items/{id:long}/audit", (long id, IReconciliationService reconciliationService) =>
{
    var audit = reconciliationService.GetAudit(id);
    return audit is null ? Results.NotFound() : Results.Ok(audit);
});

app.MapPost("/api/v1/finance/reconciliations/bulk-resolve", (
    ClaimsPrincipal user,
    BulkResolveReconciliationItemsRequest request,
    IReconciliationService reconciliationService) =>
{
    return Results.Ok(reconciliationService.BulkResolve(request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapPost("/api/v1/finance/reconciliations/items/{id:long}/manual-match", (long id, ClaimsPrincipal user, ManualMatchReconciliationItemRequest request, IReconciliationService reconciliationService) =>
{
    return Results.Ok(reconciliationService.ManualMatch(id, request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapPost("/api/v1/finance/reconciliations/items/{id:long}/override", (long id, ClaimsPrincipal user, OverrideReconciliationItemRequest request, IReconciliationService reconciliationService) =>
{
    return Results.Ok(reconciliationService.OverrideItem(id, request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapPost("/api/v1/finance/reconciliations/run", (ClaimsPrincipal user, RunReceiptReconciliationRequest request, IReconciliationService reconciliationService) =>
{
    return Results.Ok(reconciliationService.RunReceiptReconciliation(request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapPost("/api/v1/finance/reconciliations/run-settlement", (ClaimsPrincipal user, RunReceiptReconciliationRequest request, IReconciliationService reconciliationService) =>
{
    return Results.Ok(reconciliationService.RunSettlementReconciliation(request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/eta-submissions", (long id, IEtaComplianceService etaComplianceService) =>
{
    return Results.Ok(etaComplianceService.GetSubmissionLogs(id));
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/eta-payload-preview", (long id, IEtaComplianceService etaComplianceService) =>
{
    var preview = etaComplianceService.GetPayloadPreview(id);
    return preview is null ? Results.NotFound() : Results.Ok(preview);
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/eta-validation-pack", (long id, IEtaComplianceService etaComplianceService) =>
{
    var validationPack = etaComplianceService.GetSubmissionValidationPack(id);
    return validationPack is null ? Results.NotFound() : Results.Ok(validationPack);
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/eta-events", (long id, IEtaComplianceService etaComplianceService) =>
{
    return Results.Ok(etaComplianceService.GetDocumentEvents(id));
});

app.MapPost("/api/v1/finance/ar-invoices/{id:long}/eta-submit", (long id, ClaimsPrincipal user, SubmitInvoiceToEtaRequest request, IEtaComplianceService etaComplianceService) =>
{
    return Results.Ok(etaComplianceService.SubmitInvoice(id, request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapPost("/api/v1/finance/ar-invoices/{id:long}/eta-submissions/{submissionId:long}/resubmit", (
    long id,
    long submissionId,
    ClaimsPrincipal user,
    ResubmitEtaInvoiceRequest request,
    IEtaComplianceService etaComplianceService) =>
{
    return Results.Ok(etaComplianceService.ResubmitRejectedInvoice(id, submissionId, request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapPost("/api/v1/finance/ar-invoices/{id:long}/eta-submissions/{submissionId:long}/response", (
    long id,
    long submissionId,
    ClaimsPrincipal user,
    RecordEtaInvoiceResponseRequest request,
    IEtaComplianceService etaComplianceService) =>
{
    return Results.Ok(etaComplianceService.RecordInvoiceResponse(id, submissionId, request with
    {
        ActorUserId = CurrentUserAccessor.GetRequiredUserId(user)
    }));
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/eta-transmissions", (long id, IEtaComplianceService etaComplianceService) =>
{
    return Results.Ok(etaComplianceService.GetTransmissions(id));
});

app.MapGet("/api/v1/finance/eta-transmissions/{id:long}", (long id, IEtaComplianceService etaComplianceService) =>
{
    var transmission = etaComplianceService.GetTransmission(id);
    return transmission is null ? Results.NotFound() : Results.Ok(transmission);
});

app.MapPost("/api/v1/finance/ar-invoices/{id:long}/eta-submissions/{submissionId:long}/queue-transmission", (
    long id,
    long submissionId,
    ClaimsPrincipal user,
    IEtaComplianceService etaComplianceService) =>
{
    return Results.Ok(etaComplianceService.QueueTransmission(id, submissionId, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/eta-transmissions/dispatch-batch", (
    DispatchEtaTransmissionBatchRequest request,
    IEtaComplianceService etaComplianceService) =>
{
    return Results.Ok(etaComplianceService.DispatchQueuedTransmissions(request));
});

app.MapPost("/api/v1/finance/eta-transmissions/poll-batch", (
    PollEtaTransmissionBatchRequest request,
    IEtaComplianceService etaComplianceService) =>
{
    return Results.Ok(etaComplianceService.PollDispatchedTransmissions(request));
});

app.MapPost("/api/v1/finance/eta-transmissions/{id:long}/retry", (
    long id,
    ClaimsPrincipal user,
    RetryEtaTransmissionRequest request,
    IEtaComplianceService etaComplianceService) =>
{
    return Results.Ok(etaComplianceService.RetryTransmission(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/integrations/eta/auth/health", (IEtaAuthorityIntegrationService etaAuthorityIntegrationService) =>
{
    return Results.Ok(etaAuthorityIntegrationService.GetAuthHealth());
});

app.MapGet("/api/v1/finance/ar-invoices/{id:long}/eta-submissions/{submissionId:long}/authority-status", async (
    long id,
    long submissionId,
    IEtaAuthorityIntegrationService etaAuthorityIntegrationService,
    CancellationToken cancellationToken) =>
{
    return Results.Ok(await etaAuthorityIntegrationService.GetAuthoritySubmissionStatusAsync(id, submissionId, cancellationToken));
});

app.MapPut("/api/v1/integrations/eta/ping", (
    HttpRequest request,
    IEtaAuthorityIntegrationService etaAuthorityIntegrationService) =>
{
    var suppliedSecret = request.Headers.Authorization.FirstOrDefault()
        ?? request.Headers["X-ETA-PING-TOKEN"].FirstOrDefault()
        ?? request.Query["token"].FirstOrDefault();
    var echoText = request.Query["echo"].FirstOrDefault();
    var result = etaAuthorityIntegrationService.VerifyPing(suppliedSecret, echoText);
    return result.Verified ? Results.Ok(result) : Results.Unauthorized();
});

app.MapPut("/api/v1/integrations/eta/notifications/documents", async (
    HttpRequest request,
    IEtaAuthorityCallbackService etaAuthorityCallbackService) =>
{
    using var reader = new StreamReader(request.Body);
    var payloadText = await reader.ReadToEndAsync();
    var result = etaAuthorityCallbackService.ReceiveDocumentNotification(
        request.Headers.Authorization.FirstOrDefault(),
        payloadText);

    if (!result.Accepted && result.StatusCode == "AUTHORIZATION_FAILED")
    {
        return Results.Unauthorized();
    }

    if (!result.Accepted)
    {
        return Results.BadRequest(result);
    }

    return Results.Ok(result);
});

app.MapGet("/api/v1/finance/eta-notifications", (
    string? statusCode,
    IEtaNotificationOperationsService etaNotificationOperationsService) =>
{
    return Results.Ok(etaNotificationOperationsService.GetNotifications(statusCode));
});

app.MapGet("/api/v1/finance/eta-notifications/monitoring", (
    int? itemLimit,
    IEtaNotificationOperationsService etaNotificationOperationsService) =>
{
    return Results.Ok(etaNotificationOperationsService.GetMonitoring(itemLimit ?? 10));
});

app.MapGet("/api/v1/finance/eta-notifications/{id:long}", (
    long id,
    IEtaNotificationOperationsService etaNotificationOperationsService) =>
{
    var notification = etaNotificationOperationsService.GetNotification(id);
    return notification is null ? Results.NotFound() : Results.Ok(notification);
});

app.MapPost("/api/v1/finance/eta-notifications/process-batch", (
    ProcessEtaDocumentNotificationBatchRequest request,
    IEtaNotificationOperationsService etaNotificationOperationsService) =>
{
    return Results.Ok(etaNotificationOperationsService.ProcessPendingNotifications(request));
});

app.MapPost("/api/v1/finance/eta-notifications/{id:long}/reprocess", (
    long id,
    ClaimsPrincipal user,
    ReprocessEtaDocumentNotificationRequest request,
    IEtaNotificationOperationsService etaNotificationOperationsService) =>
{
    return Results.Ok(etaNotificationOperationsService.ReprocessNotification(
        id,
        CurrentUserAccessor.GetRequiredUserId(user),
        request));
});

app.MapGet("/api/v1/inventory/movements", (IInventoryMovementService inventoryMovementService) =>
{
    return Results.Ok(inventoryMovementService.GetInventoryMovements());
});

app.MapGet("/api/v1/inventory/status-controls", (IInventoryStatusControlService inventoryStatusControlService) =>
{
    return Results.Ok(inventoryStatusControlService.GetInventoryStatusControls());
});

app.MapGet("/api/v1/inventory/status-controls/{id:long}", (long id, IInventoryStatusControlService inventoryStatusControlService) =>
{
    var control = inventoryStatusControlService.GetInventoryStatusControl(id);
    return control is null ? Results.NotFound() : Results.Ok(control);
});

app.MapPost("/api/v1/inventory/status-controls", (CreateInventoryStatusControlRequest request, IInventoryStatusControlService inventoryStatusControlService) =>
{
    return Results.Ok(inventoryStatusControlService.CreateInventoryStatusControl(request));
});

app.MapPost("/api/v1/inventory/status-controls/{id:long}/submit", (long id, ClaimsPrincipal user, IInventoryStatusControlService inventoryStatusControlService) =>
{
    return Results.Ok(inventoryStatusControlService.SubmitInventoryStatusControl(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/status-controls/{id:long}/approve", (long id, ClaimsPrincipal user, IInventoryStatusControlService inventoryStatusControlService) =>
{
    return Results.Ok(inventoryStatusControlService.ApproveInventoryStatusControl(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/status-controls/{id:long}/post", (long id, ClaimsPrincipal user, IInventoryStatusControlService inventoryStatusControlService) =>
{
    return Results.Ok(inventoryStatusControlService.PostInventoryStatusControl(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/inventory/traceability/lots/{batchNumber}", (string batchNumber, IInventoryMovementService inventoryMovementService) =>
{
    var traceability = inventoryMovementService.GetLotTraceability(batchNumber);
    return traceability is null ? Results.NotFound() : Results.Ok(traceability);
});

app.MapGet("/api/v1/inventory/traceability/serials/{serialNumber}", (string serialNumber, IInventoryMovementService inventoryMovementService) =>
{
    var traceability = inventoryMovementService.GetSerialTraceability(serialNumber);
    return traceability is null ? Results.NotFound() : Results.Ok(traceability);
});

app.MapGet("/api/v1/inventory/adjustments", (IInventoryAdjustmentService inventoryAdjustmentService) =>
{
    return Results.Ok(inventoryAdjustmentService.GetInventoryAdjustments());
});

app.MapGet("/api/v1/inventory/adjustments/{id:long}", (long id, IInventoryAdjustmentService inventoryAdjustmentService) =>
{
    var adjustment = inventoryAdjustmentService.GetInventoryAdjustment(id);
    return adjustment is null ? Results.NotFound() : Results.Ok(adjustment);
});

app.MapPost("/api/v1/inventory/adjustments", (CreateInventoryAdjustmentRequest request, IInventoryAdjustmentService inventoryAdjustmentService) =>
{
    return Results.Ok(inventoryAdjustmentService.CreateInventoryAdjustment(request));
});

app.MapPost("/api/v1/inventory/adjustments/{id:long}/submit", (long id, ClaimsPrincipal user, IInventoryAdjustmentService inventoryAdjustmentService) =>
{
    return Results.Ok(inventoryAdjustmentService.SubmitInventoryAdjustment(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/adjustments/{id:long}/approve", (long id, ClaimsPrincipal user, IInventoryAdjustmentService inventoryAdjustmentService) =>
{
    return Results.Ok(inventoryAdjustmentService.ApproveInventoryAdjustment(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/adjustments/{id:long}/post", (long id, ClaimsPrincipal user, IInventoryAdjustmentService inventoryAdjustmentService) =>
{
    return Results.Ok(inventoryAdjustmentService.PostInventoryAdjustment(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/inventory/stock-counts", (IStockCountService stockCountService) =>
{
    return Results.Ok(stockCountService.GetStockCounts());
});

app.MapGet("/api/v1/inventory/stock-counts/{id:long}", (long id, IStockCountService stockCountService) =>
{
    var stockCount = stockCountService.GetStockCount(id);
    return stockCount is null ? Results.NotFound() : Results.Ok(stockCount);
});

app.MapPost("/api/v1/inventory/stock-counts", (CreateStockCountRequest request, IStockCountService stockCountService) =>
{
    return Results.Ok(stockCountService.CreateStockCount(request));
});

app.MapPost("/api/v1/inventory/stock-counts/{id:long}/submit", (long id, ClaimsPrincipal user, IStockCountService stockCountService) =>
{
    return Results.Ok(stockCountService.SubmitStockCount(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/stock-counts/{id:long}/approve", (long id, ClaimsPrincipal user, IStockCountService stockCountService) =>
{
    return Results.Ok(stockCountService.ApproveStockCount(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/stock-counts/{id:long}/post", (long id, ClaimsPrincipal user, IStockCountService stockCountService) =>
{
    return Results.Ok(stockCountService.PostStockCount(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/inventory/transfers", (IWarehouseTransferService warehouseTransferService) =>
{
    return Results.Ok(warehouseTransferService.GetWarehouseTransfers());
});

app.MapGet("/api/v1/inventory/replenishment-rules", (bool? activeOnly, IReplenishmentRuleService replenishmentRuleService) =>
{
    return Results.Ok(replenishmentRuleService.GetReplenishmentRules(activeOnly ?? false));
});

app.MapGet("/api/v1/inventory/replenishment-rules/{id:long}", (long id, IReplenishmentRuleService replenishmentRuleService) =>
{
    var rule = replenishmentRuleService.GetReplenishmentRule(id);
    return rule is null ? Results.NotFound() : Results.Ok(rule);
});

app.MapPost("/api/v1/inventory/replenishment-rules", (CreateReplenishmentRuleRequest request, IReplenishmentRuleService replenishmentRuleService) =>
{
    return Results.Ok(replenishmentRuleService.CreateReplenishmentRule(request));
});

app.MapPost("/api/v1/inventory/replenishment-rules/{id:long}/submit", (long id, ClaimsPrincipal user, IReplenishmentRuleService replenishmentRuleService) =>
{
    return Results.Ok(replenishmentRuleService.SubmitReplenishmentRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/replenishment-rules/{id:long}/approve", (long id, ClaimsPrincipal user, IReplenishmentRuleService replenishmentRuleService) =>
{
    return Results.Ok(replenishmentRuleService.ApproveReplenishmentRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/replenishment-rules/{id:long}/activate", (long id, ClaimsPrincipal user, IReplenishmentRuleService replenishmentRuleService) =>
{
    return Results.Ok(replenishmentRuleService.ActivateReplenishmentRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/replenishment-rules/evaluate", (ReplenishmentEvaluationRequest request, IReplenishmentRuleService replenishmentRuleService) =>
{
    return Results.Ok(replenishmentRuleService.EvaluateReplenishment(request));
});

app.MapPost("/api/v1/inventory/replenishment-rules/plan", (ReorderPlanningRequest request, IReplenishmentRuleService replenishmentRuleService) =>
{
    return Results.Ok(replenishmentRuleService.BuildReorderPlan(request));
});

app.MapPost("/api/v1/inventory/replenishment-rules/plan/handoff", (
    ClaimsPrincipal user,
    ReorderPlanningRequest request,
    IReplenishmentRuleService replenishmentRuleService) =>
{
    return Results.Ok(replenishmentRuleService.CreateOperationalHandoff(CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/inventory/transfers/{id:long}", (long id, IWarehouseTransferService warehouseTransferService) =>
{
    var transfer = warehouseTransferService.GetWarehouseTransfer(id);
    return transfer is null ? Results.NotFound() : Results.Ok(transfer);
});

app.MapPost("/api/v1/inventory/transfers", (CreateWarehouseTransferRequest request, IWarehouseTransferService warehouseTransferService) =>
{
    return Results.Ok(warehouseTransferService.CreateWarehouseTransfer(request));
});

app.MapPost("/api/v1/inventory/transfers/{id:long}/submit", (long id, ClaimsPrincipal user, IWarehouseTransferService warehouseTransferService) =>
{
    return Results.Ok(warehouseTransferService.SubmitWarehouseTransfer(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/transfers/{id:long}/approve", (long id, ClaimsPrincipal user, IWarehouseTransferService warehouseTransferService) =>
{
    return Results.Ok(warehouseTransferService.ApproveWarehouseTransfer(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/inventory/transfers/{id:long}/post", (long id, ClaimsPrincipal user, IWarehouseTransferService warehouseTransferService) =>
{
    return Results.Ok(warehouseTransferService.PostWarehouseTransfer(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/procurement/ap-bills/{id:long}/tax-summary", (long id, IStatutoryTaxService statutoryTaxService) =>
{
    var summary = statutoryTaxService.GetAccountsPayableBillTaxSummary(id);
    return summary is null ? Results.NotFound() : Results.Ok(summary);
});

app.MapGet("/api/v1/procurement/ap-bills/{id:long}/vat-breakdown-export", (long id, bool? download, IStatutoryTaxService statutoryTaxService) =>
{
    var export = statutoryTaxService.GetAccountsPayableBillVatBreakdownExport(id);
    return export is null
        ? Results.NotFound()
        : (download ?? false)
            ? ExportFileResultFactory.FromText(export.ContentText, export.ContentType, export.FileName)
            : Results.Ok(export);
});

app.MapGet("/api/v1/procurement/ap-bills/{id:long}/withholding-summary", (long id, IStatutoryTaxService statutoryTaxService) =>
{
    var summary = statutoryTaxService.GetAccountsPayableBillWithholdingSummary(id);
    return summary is null ? Results.NotFound() : Results.Ok(summary);
});

app.MapGet("/api/v1/procurement/ap-bills/{id:long}/withholding-export", (long id, bool? download, IStatutoryTaxService statutoryTaxService) =>
{
    var export = statutoryTaxService.GetAccountsPayableBillWithholdingExport(id);
    return export is null
        ? Results.NotFound()
        : (download ?? false)
            ? ExportFileResultFactory.FromText(export.ContentText, export.ContentType, export.FileName)
            : Results.Ok(export);
});

app.MapGet("/api/v1/procurement/ap-bills/{id:long}/statutory-evidence-export", (long id, bool? download, IStatutoryTaxService statutoryTaxService) =>
{
    var export = statutoryTaxService.GetAccountsPayableBillStatutoryEvidenceExport(id);
    return export is null
        ? Results.NotFound()
        : (download ?? false)
            ? ExportFileResultFactory.FromText(export.ContentText, export.ContentType, export.FileName)
            : Results.Ok(export);
});

app.MapGet("/api/v1/procurement/ap-bills/{id:long}/finance-review-package", (long id, IStatutoryTaxService statutoryTaxService) =>
{
    var package = statutoryTaxService.GetAccountsPayableBillFinanceReviewPackage(id);
    return package is null ? Results.NotFound() : ExportFileResultFactory.FromPackage(package);
});

app.MapGet("/api/v1/finance/gl-batches", (IGeneralLedgerService generalLedgerService) =>
{
    return Results.Ok(generalLedgerService.GetGeneralLedgerBatches());
});

app.MapGet("/api/v1/finance/accounting-rules", (bool? activeOnly, IAccountingRuleService accountingRuleService) =>
{
    return Results.Ok(accountingRuleService.GetAccountingRules(activeOnly ?? false));
});

app.MapGet("/api/v1/finance/accounting-rules/{id:long}", (long id, IAccountingRuleService accountingRuleService) =>
{
    var rule = accountingRuleService.GetAccountingRule(id);
    return rule is null ? Results.NotFound() : Results.Ok(rule);
});

app.MapPost("/api/v1/finance/accounting-rules", (CreateFinanceAccountingRuleRequest request, IAccountingRuleService accountingRuleService) =>
{
    return Results.Ok(accountingRuleService.CreateAccountingRule(request));
});

app.MapPost("/api/v1/finance/accounting-rules/{id:long}/submit", (long id, ClaimsPrincipal user, IAccountingRuleService accountingRuleService) =>
{
    return Results.Ok(accountingRuleService.SubmitAccountingRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/accounting-rules/{id:long}/approve", (long id, ClaimsPrincipal user, IAccountingRuleService accountingRuleService) =>
{
    return Results.Ok(accountingRuleService.ApproveAccountingRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/finance/accounting-rules/{id:long}/activate", (long id, ClaimsPrincipal user, IAccountingRuleService accountingRuleService) =>
{
    return Results.Ok(accountingRuleService.ActivateAccountingRule(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/integrations/endpoints", (
    bool? activeOnly,
    string? integrationProviderCode,
    string? environmentCode,
    IIntegrationEndpointRegistryService integrationEndpointRegistryService) =>
{
    return Results.Ok(integrationEndpointRegistryService.GetIntegrationEndpoints(
        activeOnly ?? false,
        integrationProviderCode,
        environmentCode));
});

app.MapGet("/api/v1/integrations/endpoints/{id:long}", (long id, IIntegrationEndpointRegistryService integrationEndpointRegistryService) =>
{
    var endpoint = integrationEndpointRegistryService.GetIntegrationEndpoint(id);
    return endpoint is null ? Results.NotFound() : Results.Ok(endpoint);
});

app.MapPost("/api/v1/integrations/endpoints", (CreateIntegrationEndpointRequest request, IIntegrationEndpointRegistryService integrationEndpointRegistryService) =>
{
    return Results.Ok(integrationEndpointRegistryService.CreateIntegrationEndpoint(request));
});

app.MapPost("/api/v1/integrations/endpoints/{id:long}/submit", (long id, ClaimsPrincipal user, IIntegrationEndpointRegistryService integrationEndpointRegistryService) =>
{
    return Results.Ok(integrationEndpointRegistryService.SubmitIntegrationEndpoint(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/integrations/endpoints/{id:long}/approve", (long id, ClaimsPrincipal user, IIntegrationEndpointRegistryService integrationEndpointRegistryService) =>
{
    return Results.Ok(integrationEndpointRegistryService.ApproveIntegrationEndpoint(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/integrations/endpoints/{id:long}/activate", (long id, ClaimsPrincipal user, IIntegrationEndpointRegistryService integrationEndpointRegistryService) =>
{
    return Results.Ok(integrationEndpointRegistryService.ActivateIntegrationEndpoint(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/integrations/outbox", (
    string? statusCode,
    string? sourceModuleCode,
    IOutboxEventService outboxEventService) =>
{
    return Results.Ok(outboxEventService.GetOutboxEvents(statusCode, sourceModuleCode));
});

app.MapGet("/api/v1/integrations/outbox/{id:long}", (long id, IOutboxEventService outboxEventService) =>
{
    var outboxEvent = outboxEventService.GetOutboxEvent(id);
    return outboxEvent is null ? Results.NotFound() : Results.Ok(outboxEvent);
});

app.MapPost("/api/v1/integrations/outbox/publish-batch", (PublishOutboxBatchRequest request, IOutboxEventService outboxEventService) =>
{
    return Results.Ok(outboxEventService.PublishPendingEvents(request));
});

app.MapPost("/api/v1/integrations/outbox/{id:long}/dead-letter", (
    long id,
    ClaimsPrincipal user,
    DeadLetterQueueItemRequest request,
    IOutboxEventService outboxEventService) =>
{
    return Results.Ok(outboxEventService.MoveOutboxEventToDeadLetter(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/integrations/outbox/{id:long}/replay", (
    long id,
    ClaimsPrincipal user,
    ReplayDeadLetterQueueItemRequest request,
    IOutboxEventService outboxEventService) =>
{
    return Results.Ok(outboxEventService.ReplayOutboxEvent(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/integrations/inbox", (
    string? statusCode,
    string? integrationProviderCode,
    IInboxMessageService inboxMessageService) =>
{
    return Results.Ok(inboxMessageService.GetInboxMessages(statusCode, integrationProviderCode));
});

app.MapGet("/api/v1/integrations/inbox/{id:long}", (long id, IInboxMessageService inboxMessageService) =>
{
    var message = inboxMessageService.GetInboxMessage(id);
    return message is null ? Results.NotFound() : Results.Ok(message);
});

app.MapPost("/api/v1/integrations/inbox/receive", (
    ClaimsPrincipal user,
    ReceiveInboxMessageRequest request,
    IInboxMessageService inboxMessageService) =>
{
    return Results.Ok(inboxMessageService.ReceiveInboxMessage(CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/integrations/inbox/process-batch", (
    ProcessInboxBatchRequest request,
    IInboxMessageService inboxMessageService) =>
{
    return Results.Ok(inboxMessageService.ProcessPendingMessages(request));
});

app.MapPost("/api/v1/integrations/inbox/{id:long}/dead-letter", (
    long id,
    ClaimsPrincipal user,
    DeadLetterQueueItemRequest request,
    IInboxMessageService inboxMessageService) =>
{
    return Results.Ok(inboxMessageService.MoveInboxMessageToDeadLetter(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/integrations/inbox/{id:long}/replay", (
    long id,
    ClaimsPrincipal user,
    ReplayDeadLetterQueueItemRequest request,
    IInboxMessageService inboxMessageService) =>
{
    return Results.Ok(inboxMessageService.ReplayInboxMessage(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/integrations/dead-letters", (
    string? queueType,
    IDeadLetterService deadLetterService) =>
{
    return Results.Ok(deadLetterService.GetDeadLetters(queueType));
});

app.MapGet("/api/v1/notifications/templates", (
    bool? activeOnly,
    string? channelCode,
    INotificationTemplateService notificationTemplateService) =>
{
    return Results.Ok(notificationTemplateService.GetTemplates(activeOnly ?? false, channelCode));
});

app.MapGet("/api/v1/notifications/templates/{id:long}", (long id, INotificationTemplateService notificationTemplateService) =>
{
    var template = notificationTemplateService.GetTemplate(id);
    return template is null ? Results.NotFound() : Results.Ok(template);
});

app.MapPost("/api/v1/notifications/templates", (
    CreateNotificationTemplateRequest request,
    INotificationTemplateService notificationTemplateService) =>
{
    return Results.Ok(notificationTemplateService.CreateTemplate(request));
});

app.MapPost("/api/v1/notifications/templates/{id:long}/submit", (
    long id,
    ClaimsPrincipal user,
    INotificationTemplateService notificationTemplateService) =>
{
    return Results.Ok(notificationTemplateService.SubmitTemplate(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/notifications/templates/{id:long}/approve", (
    long id,
    ClaimsPrincipal user,
    INotificationTemplateService notificationTemplateService) =>
{
    return Results.Ok(notificationTemplateService.ApproveTemplate(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapPost("/api/v1/notifications/templates/{id:long}/activate", (
    long id,
    ClaimsPrincipal user,
    INotificationTemplateService notificationTemplateService) =>
{
    return Results.Ok(notificationTemplateService.ActivateTemplate(id, CurrentUserAccessor.GetRequiredUserId(user)));
});

app.MapGet("/api/v1/notifications/queue", (
    string? statusCode,
    string? channelCode,
    INotificationOrchestrationService notificationOrchestrationService) =>
{
    return Results.Ok(notificationOrchestrationService.GetQueueItems(statusCode, channelCode));
});

app.MapGet("/api/v1/notifications/queue/{id:long}", (
    long id,
    INotificationOrchestrationService notificationOrchestrationService) =>
{
    var item = notificationOrchestrationService.GetQueueItem(id);
    return item is null ? Results.NotFound() : Results.Ok(item);
});

app.MapPost("/api/v1/notifications/orchestrations/enqueue", (
    ClaimsPrincipal user,
    EnqueueNotificationRequest request,
    INotificationOrchestrationService notificationOrchestrationService) =>
{
    return Results.Ok(notificationOrchestrationService.EnqueueNotification(CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/notifications/queue/send-batch", (
    NotificationSendBatchRequest request,
    INotificationOrchestrationService notificationOrchestrationService) =>
{
    return Results.Ok(notificationOrchestrationService.SendPendingBatch(request));
});

app.MapPost("/api/v1/notifications/queue/{id:long}/dead-letter", (
    long id,
    ClaimsPrincipal user,
    NotificationDeadLetterRequest request,
    INotificationOrchestrationService notificationOrchestrationService) =>
{
    return Results.Ok(notificationOrchestrationService.MoveQueueItemToDeadLetter(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapPost("/api/v1/notifications/queue/{id:long}/replay", (
    long id,
    ClaimsPrincipal user,
    NotificationReplayRequest request,
    INotificationOrchestrationService notificationOrchestrationService) =>
{
    return Results.Ok(notificationOrchestrationService.ReplayQueueItem(id, CurrentUserAccessor.GetRequiredUserId(user), request));
});

app.MapGet("/api/v1/reports/core-finance", (DateOnly? dateFrom, DateOnly? dateTo, ICoreReportingService reportingService) =>
{
    return Results.Ok(reportingService.GetCoreFinanceReport(dateFrom, dateTo));
});

app.MapGet("/api/v1/reports/finance-stakeholders", (DateOnly? dateFrom, DateOnly? dateTo, ICoreReportingService reportingService) =>
{
    return Results.Ok(reportingService.GetFinanceStakeholderSummaryReport(dateFrom, dateTo));
});

app.MapGet("/api/v1/reports/finance-stakeholders/export", (DateOnly? dateFrom, DateOnly? dateTo, ICoreReportingService reportingService) =>
{
    return Results.Text(reportingService.ExportFinanceStakeholderSummaryReportCsv(dateFrom, dateTo), "text/csv");
});

app.MapGet("/api/v1/reports/finance-stakeholders/{stakeholderType}/{stakeholderId:long}", (
    string stakeholderType,
    long stakeholderId,
    string currencyCode,
    DateOnly? dateFrom,
    DateOnly? dateTo,
    ICoreReportingService reportingService) =>
{
    return Results.Ok(reportingService.GetFinanceStakeholderDetailReport(stakeholderType, stakeholderId, currencyCode, dateFrom, dateTo));
});

app.MapGet("/api/v1/reports/finance-stakeholders/{stakeholderType}/{stakeholderId:long}/export", (
    string stakeholderType,
    long stakeholderId,
    string currencyCode,
    DateOnly? dateFrom,
    DateOnly? dateTo,
    ICoreReportingService reportingService) =>
{
    return Results.Text(reportingService.ExportFinanceStakeholderDetailReportCsv(stakeholderType, stakeholderId, currencyCode, dateFrom, dateTo), "text/csv");
});

app.MapGet("/api/v1/reports/finance-statements/{statementCode}", (
    string statementCode,
    DateOnly? dateFrom,
    DateOnly? dateTo,
    DateOnly? asOfDate,
    ICoreReportingService reportingService) =>
{
    return Results.Ok(reportingService.GetFinancialStatementReport(statementCode, dateFrom, dateTo, asOfDate));
});

app.MapGet("/api/v1/reports/finance-statements/{statementCode}/export", (
    string statementCode,
    string? format,
    DateOnly? dateFrom,
    DateOnly? dateTo,
    DateOnly? asOfDate,
    ICoreReportingService reportingService) =>
{
    var export = reportingService.ExportFinancialStatement(statementCode, format ?? "CSV", dateFrom, dateTo, asOfDate);
    return Results.File(export.ContentBytes, export.ContentType, export.FileName);
});

app.MapGet("/api/v1/reports/core-finance/export", (DateOnly? dateFrom, DateOnly? dateTo, ICoreReportingService reportingService) =>
{
    return Results.Text(reportingService.ExportCoreFinanceReportCsv(dateFrom, dateTo), "text/csv");
});

app.MapGet("/api/v1/reports/core-operations", (DateOnly? dateFrom, DateOnly? dateTo, ICoreReportingService reportingService) =>
{
    return Results.Ok(reportingService.GetCoreOperationsReport(dateFrom, dateTo));
});

app.MapGet("/api/v1/reports/core-operations/export", (DateOnly? dateFrom, DateOnly? dateTo, ICoreReportingService reportingService) =>
{
    return Results.Text(reportingService.ExportCoreOperationsReportCsv(dateFrom, dateTo), "text/csv");
});

app.MapGet("/api/v1/reports/islamic-finance/pipeline", (
    DateOnly? dateFrom,
    DateOnly? dateTo,
    long? partnerLenderId,
    ICoreReportingService reportingService) =>
{
    return Results.Ok(reportingService.GetIslamicFinancePipelineReport(dateFrom, dateTo, partnerLenderId));
});

app.MapGet("/api/v1/reports/islamic-finance/pipeline/export", (
    DateOnly? dateFrom,
    DateOnly? dateTo,
    long? partnerLenderId,
    ICoreReportingService reportingService) =>
{
    return Results.Text(reportingService.ExportIslamicFinancePipelineReportCsv(dateFrom, dateTo, partnerLenderId), "text/csv");
});

app.MapGet("/api/v1/reports/aging/ap", (DateOnly? asOfDate, ICoreReportingService reportingService) =>
{
    return Results.Ok(reportingService.GetAccountsPayableAgingReport(asOfDate));
});

app.MapGet("/api/v1/reports/aging/ap/export", (DateOnly? asOfDate, ICoreReportingService reportingService) =>
{
    return Results.Text(reportingService.ExportAccountsPayableAgingReportCsv(asOfDate), "text/csv");
});

app.MapGet("/api/v1/reports/aging/ar", (DateOnly? asOfDate, ICoreReportingService reportingService) =>
{
    return Results.Ok(reportingService.GetAccountsReceivableAgingReport(asOfDate));
});

app.MapGet("/api/v1/reports/aging/ar/export", (DateOnly? asOfDate, ICoreReportingService reportingService) =>
{
    return Results.Text(reportingService.ExportAccountsReceivableAgingReportCsv(asOfDate), "text/csv");
});

app.MapGet("/api/v1/reports/snapshots", (string? reportCode, ICoreReportingService reportingService) =>
{
    return Results.Ok(reportingService.GetReportingSnapshots(reportCode));
});

app.MapGet("/api/v1/reports/snapshots/{id:long}", (long id, ICoreReportingService reportingService) =>
{
    var snapshot = reportingService.GetReportingSnapshot(id);
    return snapshot is null ? Results.NotFound() : Results.Ok(snapshot);
});

app.MapPost("/api/v1/reports/snapshots", (ClaimsPrincipal user, CreateReportingSnapshotRequest request, ICoreReportingService reportingService) =>
{
    return Results.Ok(reportingService.GenerateReportingSnapshot(CurrentUserAccessor.GetRequiredUserId(user), request));
});

LogStartup("Route mapping completed. Entering app.Run().");
app.Run();

static bool TryGetExternalPartyId(PathString path, out long partyId)
{
    partyId = 0L;
    var segments = path.Value?.Split('/', StringSplitOptions.RemoveEmptyEntries);
    if (segments is null || segments.Length < 5)
    {
        return false;
    }

    return string.Equals(segments[0], "api", StringComparison.OrdinalIgnoreCase)
        && string.Equals(segments[1], "v1", StringComparison.OrdinalIgnoreCase)
        && string.Equals(segments[2], "external", StringComparison.OrdinalIgnoreCase)
        && string.Equals(segments[3], "parties", StringComparison.OrdinalIgnoreCase)
        && long.TryParse(segments[4], out partyId);
}

static bool RequiresFinanceRole(PathString path)
{
    if (!path.StartsWithSegments("/api/v1", out var remainder))
    {
        return false;
    }

    return (remainder.StartsWithSegments("/finance", StringComparison.OrdinalIgnoreCase)
            && !remainder.StartsWithSegments("/finance/eta-notifications", StringComparison.OrdinalIgnoreCase))
        || remainder.StartsWithSegments("/reports/finance-stakeholders", StringComparison.OrdinalIgnoreCase)
        || remainder.StartsWithSegments("/reports/finance-statements", StringComparison.OrdinalIgnoreCase)
        || remainder.StartsWithSegments("/reports/core-finance", StringComparison.OrdinalIgnoreCase)
        || remainder.StartsWithSegments("/reports/aging/ap", StringComparison.OrdinalIgnoreCase)
        || remainder.StartsWithSegments("/reports/aging/ar", StringComparison.OrdinalIgnoreCase);
}

static bool RequiresEtaNotificationOperationsRole(PathString path)
{
    if (!path.StartsWithSegments("/api/v1", out var remainder))
    {
        return false;
    }

    return remainder.StartsWithSegments("/finance/eta-notifications", StringComparison.OrdinalIgnoreCase);
}

static bool RequiresCounterpartyGovernanceRole(PathString path)
{
    if (!path.StartsWithSegments("/api/v1", out var remainder))
    {
        return false;
    }

    var remainderValue = remainder.Value ?? string.Empty;
    return remainderValue.Equals("/suppliers", StringComparison.OrdinalIgnoreCase)
        || remainderValue.StartsWith("/suppliers/", StringComparison.OrdinalIgnoreCase)
        || remainderValue.Equals("/customers", StringComparison.OrdinalIgnoreCase)
        || remainderValue.StartsWith("/customers/", StringComparison.OrdinalIgnoreCase);
}

static bool RequiresIslamicFinanceOfficerRole(PathString path)
{
    if (!path.StartsWithSegments("/api/v1", out var remainder))
    {
        return false;
    }

    return remainder.StartsWithSegments("/islamic-finance/officer-workbench", StringComparison.OrdinalIgnoreCase);
}

static bool RequiresIamAdminRole(PathString path)
{
    return path.StartsWithSegments("/api/v1/iam", StringComparison.OrdinalIgnoreCase);
}

static bool IsIamAdministrationPath(PathString path)
{
    if (!path.StartsWithSegments("/api/v1", out var remainder))
    {
        return false;
    }

    return remainder.StartsWithSegments("/iam", StringComparison.OrdinalIgnoreCase)
        || remainder.StartsWithSegments("/auth/me", StringComparison.OrdinalIgnoreCase)
        || remainder.StartsWithSegments("/demo/bootstrap", StringComparison.OrdinalIgnoreCase);
}

static bool IsSuperAdminOnlyIdentity(ClaimsPrincipal user) =>
    HasAnyRole(user, "SUPER_ADMIN")
    || string.Equals(user.FindFirstValue(ClaimTypes.Name), "administrator@uat.cashline.test", StringComparison.OrdinalIgnoreCase)
    || string.Equals(user.FindFirstValue(ClaimTypes.Name), "ADMINISTRATOR", StringComparison.OrdinalIgnoreCase);

static bool IsSystemOwnerOnlyIdentity(ClaimsPrincipal user) =>
    HasAnyRole(user, "SYSTEM_OWNER")
    || string.Equals(user.FindFirstValue(ClaimTypes.Name), "system.owner@uat.cashline.test", StringComparison.OrdinalIgnoreCase);

static bool IsAccountingOfficeIdentity(ClaimsPrincipal user) =>
    HasAnyRole(user, "ACCOUNTING_OFFICE_USER", "ACCOUNTING_OFFICE_SUPERVISOR");

static bool IsAdministratorManagedUser(AdminUserResponse user) =>
    user.RoleCodes.Contains("SUPER_ADMIN", StringComparer.OrdinalIgnoreCase);

static bool IsAccountingOfficeManagedUser(AdminUserResponse user) =>
    user.RoleCodes.Contains("ACCOUNTING_OFFICE_USER", StringComparer.OrdinalIgnoreCase)
    || user.RoleCodes.Contains("ACCOUNTING_OFFICE_SUPERVISOR", StringComparer.OrdinalIgnoreCase);

static bool IsSystemOwnerManagedUser(AdminUserResponse user) =>
    IsAdministratorManagedUser(user) || IsAccountingOfficeManagedUser(user);

static bool IsAdministratorGovernanceMenuSection(AdminPortalMenuSectionResponse section) =>
    section.Functions.Any(function =>
        string.Equals(function.FunctionCode, "CREATE_ADMINISTRATORS", StringComparison.OrdinalIgnoreCase)
        || string.Equals(function.FunctionCode, "GOVERN_ADMINISTRATORS", StringComparison.OrdinalIgnoreCase)
        || string.Equals(function.FunctionCode, "EXPORT_ADMINISTRATOR_REPORTS", StringComparison.OrdinalIgnoreCase));

static bool IsAccountingOfficeGovernanceMenuSection(AdminPortalMenuSectionResponse section) =>
    section.Functions.Any(function =>
        string.Equals(function.FunctionCode, "ACCOUNTING_OFFICE_DASHBOARD", StringComparison.OrdinalIgnoreCase)
        || string.Equals(function.FunctionCode, "ACCOUNTING_OFFICE_CLIENT_ONBOARDING", StringComparison.OrdinalIgnoreCase)
        || string.Equals(function.FunctionCode, "ACCOUNTING_OFFICE_CLIENT_FINANCE", StringComparison.OrdinalIgnoreCase)
        || string.Equals(function.FunctionCode, "ACCOUNTING_OFFICE_ETA_SUBMISSIONS", StringComparison.OrdinalIgnoreCase)
        || string.Equals(function.FunctionCode, "ACCOUNTING_OFFICE_REPORTING", StringComparison.OrdinalIgnoreCase));

static bool IsSystemOwnerVisibleMenuSection(AdminPortalMenuSectionResponse section) =>
    IsAdministratorGovernanceMenuSection(section) || IsAccountingOfficeGovernanceMenuSection(section);

static string? ValidateAdministratorCreationAuthority(ClaimsPrincipal actor, CreateAdminManagedUserRequest request)
{
    var requestedRoles = request.RoleCodes
        .Select(roleCode => roleCode.Trim().ToUpperInvariant())
        .Where(roleCode => !string.IsNullOrWhiteSpace(roleCode))
        .Distinct(StringComparer.OrdinalIgnoreCase)
        .ToArray();
    var createsAdministrator = requestedRoles.Contains("SUPER_ADMIN", StringComparer.OrdinalIgnoreCase);
    var createsAccountingOffice = requestedRoles.Contains("ACCOUNTING_OFFICE_USER", StringComparer.OrdinalIgnoreCase)
        || requestedRoles.Contains("ACCOUNTING_OFFICE_SUPERVISOR", StringComparer.OrdinalIgnoreCase);
    var createsSystemOwner = requestedRoles.Contains("SYSTEM_OWNER", StringComparer.OrdinalIgnoreCase);

    if (IsSystemOwnerOnlyIdentity(actor))
    {
        if (!string.Equals(request.UserTypeCode, UserTypeCode.Internal, StringComparison.OrdinalIgnoreCase)
            || requestedRoles.Length != 1
            || (!createsAdministrator && !createsAccountingOffice))
        {
            return "System Owner can create Administrator or Accounting Office users only.";
        }

        return null;
    }

    if (createsAdministrator || createsAccountingOffice || createsSystemOwner)
    {
        return "Only System Owner can create Administrator, Accounting Office, or System Owner governed accounts.";
    }

    return null;
}

static string? ValidateAdministratorGovernanceAuthority(
    ClaimsPrincipal actor,
    AdminUserResponse? targetUser,
    IReadOnlyCollection<string>? requestedRoleCodes)
{
    if (targetUser is null)
    {
        return "Managed user was not found.";
    }

    if (IsSystemOwnerOnlyIdentity(actor))
    {
        if (!IsSystemOwnerManagedUser(targetUser))
        {
            return "System Owner can govern Administrator or Accounting Office users only.";
        }

        if (requestedRoleCodes is not null)
        {
            var requestedRoles = requestedRoleCodes
                .Select(roleCode => roleCode.Trim().ToUpperInvariant())
                .Where(roleCode => !string.IsNullOrWhiteSpace(roleCode))
                .Distinct(StringComparer.OrdinalIgnoreCase)
                .ToArray();
            if (requestedRoles.Length != 1
                || !(requestedRoles.Contains("SUPER_ADMIN", StringComparer.OrdinalIgnoreCase)
                    || requestedRoles.Contains("ACCOUNTING_OFFICE_USER", StringComparer.OrdinalIgnoreCase)
                    || requestedRoles.Contains("ACCOUNTING_OFFICE_SUPERVISOR", StringComparer.OrdinalIgnoreCase)))
            {
                return "System Owner cannot assign roles outside Administrator or Accounting Office governance.";
            }
        }

        return null;
    }

    if (requestedRoleCodes?.Any(roleCode =>
            string.Equals(roleCode, "SYSTEM_OWNER", StringComparison.OrdinalIgnoreCase)
            || string.Equals(roleCode, "SUPER_ADMIN", StringComparison.OrdinalIgnoreCase)
            || string.Equals(roleCode, "ACCOUNTING_OFFICE_USER", StringComparison.OrdinalIgnoreCase)
            || string.Equals(roleCode, "ACCOUNTING_OFFICE_SUPERVISOR", StringComparison.OrdinalIgnoreCase)) == true)
    {
        return "Only System Owner can assign Administrator or Accounting Office governance roles.";
    }

    return null;
}

static bool HasAnyRole(ClaimsPrincipal user, params string[] roleCodes)
{
    if (roleCodes.Length == 0)
    {
        return false;
    }

    // Be resilient: some hosts/middleware can misconfigure RoleClaimType, but we always emit both
    // ClaimTypes.Role and ApiClaimTypes.RoleCode in our bearer handler.
    var assigned = user.FindAll(ClaimTypes.Role)
        .Concat(user.FindAll(ApiClaimTypes.RoleCode))
        .Select(claim => claim.Value)
        .Where(value => !string.IsNullOrWhiteSpace(value))
        .ToHashSet(StringComparer.OrdinalIgnoreCase);

    return roleCodes.Any(assigned.Contains);
}

static bool HasAnyFunction(ClaimsPrincipal user, IReadOnlyCollection<string> functionCodes)
{
    if (functionCodes.Count == 0 || HasAnyRole(user, "SUPER_ADMIN"))
    {
        return true;
    }

    var assignedFunctions = user.FindAll(ApiClaimTypes.FunctionCode)
        .Select(claim => claim.Value)
        .ToHashSet(StringComparer.OrdinalIgnoreCase);
    return functionCodes.Any(assignedFunctions.Contains);
}

static bool TryResolveRequiredFunctionCodes(PathString path, out IReadOnlyCollection<string> functionCodes)
{
    functionCodes = Array.Empty<string>();
    if (!path.StartsWithSegments("/api/v1", out var remainder))
    {
        return false;
    }

    var value = remainder.Value ?? string.Empty;
    if (value.StartsWith("/accounting-office", StringComparison.OrdinalIgnoreCase))
    {
        functionCodes = new[]
        {
            "ACCOUNTING_OFFICE_DASHBOARD",
            "ACCOUNTING_OFFICE_CLIENT_ONBOARDING",
            "ACCOUNTING_OFFICE_CLIENT_FINANCE",
            "ACCOUNTING_OFFICE_ETA_SUBMISSIONS",
            "ACCOUNTING_OFFICE_REPORTING"
        };
        return true;
    }

    // Function enforcement is currently targeted at external-portal routes (Supplier/Customer)
    // plus a few governed internal/reporting surfaces. Avoid broad substring checks that would
    // unintentionally block internal modules (e.g., /sales/orders contains "/orders").
    if (!value.StartsWith("/external", StringComparison.OrdinalIgnoreCase))
    {
        if (value.StartsWith("/reports", StringComparison.OrdinalIgnoreCase))
        {
            functionCodes = new[] { "FINANCE_REPORTING", "OPERATIONAL_REPORTING", "EXPORT_USER_ADMIN_REPORTS", "EXPORT_ADMINISTRATOR_REPORTS" };
            return true;
        }

        return false;
    }

    if (value.Contains("/supplier-profile", StringComparison.OrdinalIgnoreCase))
    {
        functionCodes = new[] { "SUPPLIER_ONBOARDING", "SUPPLIER_DOCUMENTS" };
        return true;
    }

    if (value.Contains("/customer-profile", StringComparison.OrdinalIgnoreCase))
    {
        functionCodes = new[] { "CUSTOMER_ONBOARDING", "CUSTOMER_DOCUMENTS" };
        return true;
    }

    if (value.Contains("/purchase-orders", StringComparison.OrdinalIgnoreCase)
        || value.Contains("/rfq-invitations", StringComparison.OrdinalIgnoreCase)
        || value.Contains("/quotations", StringComparison.OrdinalIgnoreCase))
    {
        functionCodes = new[] { "SUPPLIER_PURCHASE_ORDERS" };
        return true;
    }

    if (value.Contains("/invoices", StringComparison.OrdinalIgnoreCase))
    {
        functionCodes = new[] { "SUPPLIER_INVOICES", "CUSTOMER_PAYMENTS" };
        return true;
    }

    if (value.Contains("/payments", StringComparison.OrdinalIgnoreCase))
    {
        functionCodes = new[] { "SUPPLIER_INVOICES", "CUSTOMER_PAYMENTS" };
        return true;
    }

    if (value.Contains("/reports-statements", StringComparison.OrdinalIgnoreCase)
        || value.Contains("/statement", StringComparison.OrdinalIgnoreCase))
    {
        functionCodes = new[] { "SUPPLIER_STATEMENTS", "CUSTOMER_STATEMENTS" };
        return true;
    }

    if (value.Contains("/orders", StringComparison.OrdinalIgnoreCase))
    {
        functionCodes = new[] { "SUPPLIER_PURCHASE_ORDERS", "CUSTOMER_ORDERS" };
        return true;
    }

    if (value.Contains("/service-requests", StringComparison.OrdinalIgnoreCase))
    {
        functionCodes = new[] { "CUSTOMER_ORDERS" };
        return true;
    }

    if (value.Contains("/financing", StringComparison.OrdinalIgnoreCase))
    {
        functionCodes = new[] { "SUPPLIER_INVOICES", "CUSTOMER_PAYMENTS" };
        return true;
    }

    return false;
}

static async Task<ComplianceUploadHttpRequest> ReadComplianceUploadRequestAsync(HttpRequest request, CancellationToken cancellationToken)
{
    if (!request.HasFormContentType)
    {
        throw new InvalidOperationException("Compliance document upload requires multipart form data.");
    }

    var form = await request.ReadFormAsync(cancellationToken);
    var documentType = form["documentType"].ToString();
    var subjectTypeCode = form["subjectTypeCode"].ToString();
    var file = form.Files.GetFile("file");

    if (string.IsNullOrWhiteSpace(documentType))
    {
        throw new InvalidOperationException("Compliance document upload requires documentType.");
    }

    if (file is null || file.Length == 0)
    {
        throw new InvalidOperationException("Compliance document upload requires a non-empty file.");
    }

    return new ComplianceUploadHttpRequest(
        documentType.Trim(),
        string.IsNullOrWhiteSpace(subjectTypeCode) ? null : subjectTypeCode.Trim(),
        file);
}

static string NormalizeUploadScope(string prefix, string? subjectTypeCode)
{
    if (string.IsNullOrWhiteSpace(subjectTypeCode))
    {
        return prefix;
    }

    var suffix = new string(subjectTypeCode
        .Trim()
        .ToLowerInvariant()
        .Select(character => char.IsLetterOrDigit(character) ? character : '-')
        .ToArray())
        .Trim('-');

    return string.IsNullOrWhiteSpace(suffix) ? prefix : $"{prefix}-{suffix}";
}

static void LogStartup(string message)
{
    Console.Error.WriteLine($"[Startup] {message}");
}

internal sealed record ComplianceUploadHttpRequest(
    string DocumentType,
    string? SubjectTypeCode,
    IFormFile File);

public partial class Program
{
}
