using System; using System.Collections.Generic; using System.Data.Odbc; using System.Linq; using System.Text; using System.Text.RegularExpressions; using AS400API.Infrastructure; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; namespace AS400API.Endpoints; public static class ORDUAGEndpoint { private static readonly string[] ColumnNames = [ "AG_CODE_COMPANY", "AG_CODE_CURRENCY", "AG_CODE_NUMBER", "AGENT_AGENCY", "AGENT_HOME_NAAD", "AGENT_MAIL_NAAD", "AGENT_PHONE", "AGENT_STAT", "AGENT_START_DATE", "AGENT_DATE_TERM", "AGENT_FILLER_01", "AGENT_QUALITY_BONUS", "AGENT_MARKET_BONUS", "AGENT_NON_HOUSED_COMP", "AGENT_OTHER_COMP", "AGENT_FINANCE", "AGENT_FILLER_02", "AGENT_PAY_NOPAY", "AGENT_HOLD_BACK", "AGENT_DEVELOPMENT_AMT", "AGENT_NON_MED_PRIV", "AGENT_FRINGE_BENEFIT", "AGENT_FILLER_03", "AGENT_REGION", "AGENT_SPONSOR_LIC", "AGENT_PRIM_LIC_NO", "AGENT_QUALIFICATION", "AGENT_PREV_ID", "AGENT_FILLER_05", "AGENT_FYR_COMM_CURMTH", "AGENT_FYR_COMM_YTD", "AGENT_RENEWAL_COMM_CURMTH", "AGENT_RENEWAL_COMM_YTD", "AGENT_SERVFEE_CURMTH", "AGENT_SERVFEE_YTD", "AGENT_SINGPRM_CURMTH", "AGENT_SINGPRM_YTD", "AGENT_OVERRIDE_CURMTH", "AGENT_OVERRIDE_YTD", "AGENT_PAY_DED_CURMTH", "AGENT_PAY_DED_YTD", "AGENT_PAYABLE_BALANCE_YTD", "AGENT_NET_FYR_COMM1", "AGENT_NET_FYR_COMM2", "AGENT_NET_FYR_COMM3", "AGENT_NET_FYR_COMM4", "AGENT_NET_FYR_COMM5", "AGENT_NET_FYR_COMM6", "AGENT_NET_FYR_COMM7", "AGENT_NET_FYR_COMM8", "AGENT_NET_FYR_COMM9", "AGENT_NET_FYR_COMM10", "AGENT_NET_FYR_COMM11", "AGENT_NET_FYR_COMM12", "AGENT_ASGNMT_MADE_AMT", "AGENT_ASGNMT_REC_AMT", "AGENT_NET_FYR_LIFE_COMM1", "AGENT_NET_FYR_LIFE_COMM2", "AGENT_NET_FYR_LIFE_COMM3", "AGENT_NET_FYR_LIFE_COMM4", "AGENT_NET_FYR_LIFE_COMM5", "AGENT_NET_FYR_LIFE_COMM6", "AGENT_NET_FYR_LIFE_COMM7", "AGENT_NET_FYR_LIFE_COMM8", "AGENT_NET_FYR_LIFE_COMM9", "AGENT_NET_FYR_LIFE_COMM10", "AGENT_NET_FYR_LIFE_COMM11", "AGENT_NET_FYR_LIFE_COMM12", "AGENT_FYC_SINGPRM_CURMTH", "AGENT_FYC_SINGPRM_YTD", "AGENT_FYR_LIFE_COMM_CURMTH", "AGENT_FYR_LIFE_COMM_YTD", "AGENT_REN_LIFE_COMM_CURMTH", "AGENT_REN_LIFE_COMM_YTD", "AGENT_QUALITY_BON_CURMTH", "AGENT_QUALITY_BON_YTD", "AGENT_MARKET_BON_CURMTH", "AGENT_MARKET_BON_YTD", "AGENT_NON_HOUSED_CURMTH", "AGENT_NON_HOUSED_YTD", "AGENT_APP_CNT_LSTMTH", "AGENT_APP_CNT_YTM", "AGENT_TOT_PREM_WRIT_LSTMTH", "AGENT_TOT_PREM_WRIT_YTM", "AGENT_LIFE_PREM_WRIT_LSTMTH", "AGENT_LIFE_PREM_WRIT_YTM", "AGENT_TOT_FYP_CURMTH", "AGENT_TOT_FYP_YTD", "AGENT_TOT_REN_CURMTH", "AGENT_TOT_REN_YTD", "AGENT_PERSISTENCY1", "AGENT_PERSISTENCY2", "AGENT_PERSISTENCY3", "AGENT_PERSISTENCY4", "AGENT_PRODUCTION1", "AGENT_PRODUCTION2", "AGENT_PRODUCTION3", "AGENT_PRODUCTION4", "AGENT_MDRT1", "AGENT_MDRT2", "AGENT_MDRT3", "AGENT_MDRT4", "AGENT_CONVENTIONS1", "AGENT_CONVENTIONS2", "AGENT_CONVENTIONS3", "AGENT_CONVENTIONS4", "AGENT_APPTIVITY_AWARD1", "AGENT_APPTIVITY_AWARD2", "AGENT_APPTIVITY_AWARD3", "AGENT_APPTIVITY_AWARD4", "AGENT_NQA1", "AGENT_NQA2", "AGENT_NQA3", "AGENT_NQA4", "AG_BLACKLIST_RSN", "AG_TAX_NUMBER", "AG_DIST_CHANEL_CODE", "AGENT_LIAISON_OFF", "AGENT_FILLER_07", "AG_LIC_FPO", "AG_LIC_START_DATE", "AG_LIC_END_DATE", "AG_GUARANTOR_NO", "AG_GUARANTOR_SW", "AG_BANK_ACCOUNT", "AG_PREV_TAX_RATE", "AG_CURR_TAX_RATE", "AG_PRESERVE_AGENT", "AG_LIC_REQ_DATE", "AG_BLACKLIST_IND", "AGENT_FILLER_06" ]; private static readonly Regex LibraryNamePattern = new("^[A-Z0-9_]+$", RegexOptions.Compiled | RegexOptions.IgnoreCase); public static RouteGroupBuilder MapORDUAGEndpoints(this RouteGroupBuilder group) { group.MapGet("/v1/orduag/query", async ( [AsParameters] OrduagQuery query, OdbcConnection conn, ILoggerFactory loggerFactory) => { var logger = loggerFactory.CreateLogger("ORDUAGEndpoint"); try { await conn.OpenAsync(); var page = query.Page.GetValueOrDefault(1); if (page < 1) { logger.LogWarning("Invalid page value {Page}; defaulting to 1", query.Page); page = 1; } var pageSize = query.PageSize.GetValueOrDefault(50); pageSize = Math.Clamp(pageSize, 1, 500); var offsetLong = (long)(page - 1) * pageSize; if (offsetLong > int.MaxValue) { return Results.BadRequest(new { error = "Requested page is too large." }); } var offset = (int)offsetLong; var sqlBuilder = new StringBuilder(); sqlBuilder.AppendLine("SELECT"); sqlBuilder.AppendLine(string.Join(",\n", ColumnNames.Select(column => $" {column}"))); sqlBuilder.AppendLine("FROM CP3FPRD.ORDUAG"); sqlBuilder.AppendLine("WHERE 1 = 1"); var parameterValues = new List(); if (!string.IsNullOrWhiteSpace(query.CodeNumber)) { sqlBuilder.AppendLine(" AND AG_CODE_NUMBER = ?"); parameterValues.Add(query.CodeNumber.Trim()); } if (!string.IsNullOrWhiteSpace(query.AgentAgency)) { sqlBuilder.AppendLine(" AND AGENT_AGENCY = ?"); parameterValues.Add(query.AgentAgency.Trim()); } if (!string.IsNullOrWhiteSpace(query.AgentStat)) { sqlBuilder.AppendLine(" AND AGENT_STAT = ?"); parameterValues.Add(query.AgentStat.Trim()); } sqlBuilder.AppendLine("ORDER BY AG_CODE_NUMBER"); sqlBuilder.AppendLine("OFFSET ? ROWS FETCH NEXT ? ROWS ONLY"); parameterValues.Add(offset); parameterValues.Add(pageSize); await using var command = conn.CreateCommand(); command.CommandText = sqlBuilder.ToString(); foreach (var value in parameterValues) { var parameter = command.CreateParameter(); parameter.Value = value; command.Parameters.Add(parameter); } var rows = new List>(); await using (var reader = await command.ExecuteReaderAsync()) { while (await reader.ReadAsync()) { var row = new Dictionary(StringComparer.OrdinalIgnoreCase); for (var i = 0; i < reader.FieldCount; i++) { var value = reader.GetNormalizedValue(i); row[reader.GetName(i)] = value!; } rows.Add(row); } } logger.LogInformation( "Fetched {Count} ORDUAG rows with filters codeNumber={CodeNumber}, agency={Agency}, status={Status}, page={Page}, pageSize={PageSize}", rows.Count, query.CodeNumber, query.AgentAgency, query.AgentStat, page, pageSize); var formatted = rows.Select(dict => dict.ToCamelCaseDictionary()).ToList(); return Results.Ok(formatted); } catch (Exception ex) { logger.LogError(ex, "Failed to list tables for AS/400 ORDUAG"); return Results.Problem($"Failed to list tables: {ex.Message}"); } }) // .RequireAuthorization(AuthPolicies.RequireOperator) .WithSummary("List tables for a specific AS/400 library (schema)"); return group; } public sealed class OrduagQuery { public string? CodeNumber { get; init; } public string? AgentAgency { get; init; } public string? AgentStat { get; init; } public int? Page { get; init; } public int? PageSize { get; init; } } }