defmodule DaProductApp.Switch.Config do @moduledoc """ Configuration management for the Switch system. Provides centralized configuration for message handlers, routing, connectors, and other switch components with environment-specific settings and feature toggles. """ @doc """ Gets the message handler configuration. """ def get_message_handler_config do Application.get_env(:da_product_app, :switch_message_handler, %{ # Handler selection handler: :iso8583b, # :iso8583b, :legacy, :auto # Fallback configuration enable_fallback: true, fallback_handler: :legacy, # Performance settings timeout_ms: 30_000, max_message_size: 8192, # Validation settings strict_validation: false, enable_business_rules: true, # TPDU configuration tpdu: %{ enabled: true, patterns: [ %{ pattern: <<0x60, 0x00, 0x78, 0x20, 0x00>>, length: 5, description: "Mercury Device TPDU" }, %{ pattern: <<0x60, 0x00, 0x78, 0x00, 0x00>>, length: 5, description: "Alternative Mercury TPDU" } ] }, # Error handling error_handling: %{ max_parse_retries: 3, enable_error_recovery: true, log_parse_errors: true, create_error_responses: true } }) end @doc """ Gets the protocol handler configuration. """ def get_protocol_config do Application.get_env(:da_product_app, :switch_protocol, %{ # Connection settings tcp: %{ port: 8583, max_connections: 100, timeout_ms: 30_000, socket_options: [ {:active, :once}, {:packet, :raw}, {:reuseaddr, true}, {:nodelay, true} ] }, # SSL/TLS settings ssl: %{ enabled: false, port: 8584, certfile: nil, keyfile: nil, cacertfile: nil, verify: :verify_peer }, # Message processing processing: %{ buffer_size: 16384, max_buffer_size: 65536, message_framing: :length_header, # :length_header, :delimiter enable_keepalive: true }, # Logging and monitoring logging: %{ log_connections: true, log_raw_data: false, # Set to true for debugging log_message_flow: true, log_performance: true } }) end @doc """ Gets the routing configuration. """ def get_routing_config do Application.get_env(:da_product_app, :switch_routing, %{ # Router selection router: :enhanced, # :enhanced, :legacy # Network Manager Integration use_network_manager: true, # Enable upstream network routing # Routing strategies strategies: [ :processing_code, :card_type, :bin_range, :merchant_config, :default ], # Load balancing load_balancing: %{ enabled: true, strategy: :round_robin, # :round_robin, :weighted, :least_connections health_check_interval: 30_000 }, # Failover configuration failover: %{ enabled: true, max_retries: 3, retry_delay_ms: 1000, circuit_breaker: %{ enabled: true, failure_threshold: 5, timeout_ms: 60_000 } }, # BIN range routing (for enhanced router) bin_routing: %{ enabled: true, ranges: %{ "411111" => %{connector: :visa, priority: 1}, "555555" => %{connector: :mastercard, priority: 1}, "378282" => %{connector: :amex, priority: 1}, "6011" => %{connector: :discover, priority: 1} } } }) end @doc """ Gets the network manager configuration for upstream connectivity. """ def get_network_manager_config do Application.get_env(:da_product_app, :network_manager, %{ networks: [ %{ type: :visa, host: System.get_env("VISA_HOST") || "visa-gateway.example.com", port: String.to_integer(System.get_env("VISA_PORT") || "8583"), config: %{ timeout: 30_000, max_connections: 10, ssl_enabled: String.to_atom(System.get_env("VISA_SSL") || "false"), heartbeat_interval: 60_000 } }, %{ type: :mastercard, host: System.get_env("MASTERCARD_HOST") || "mastercard-gateway.example.com", port: String.to_integer(System.get_env("MASTERCARD_PORT") || "8583"), config: %{ timeout: 30_000, max_connections: 10, ssl_enabled: String.to_atom(System.get_env("MASTERCARD_SSL") || "false"), heartbeat_interval: 60_000, ebcdic_subfields: true # Enable EBCDIC subfield processing } } ], bin_routes: %{ # VISA BIN ranges "4" => :visa, # All 4xxx cards "40" => :visa, "41" => :visa, "42" => :visa, "43" => :visa, "44" => :visa, "45" => :visa, "46" => :visa, "47" => :visa, "48" => :visa, "49" => :visa, # MasterCard BIN ranges "5" => :mastercard, # All 5xxx cards "50" => :mastercard, "51" => :mastercard, "52" => :mastercard, "53" => :mastercard, "54" => :mastercard, "55" => :mastercard, # MasterCard 2-series "2221" => :mastercard, "2222" => :mastercard, "2223" => :mastercard, "2224" => :mastercard, "2225" => :mastercard, "2226" => :mastercard, "2227" => :mastercard, "2228" => :mastercard, "2229" => :mastercard, # Default routing "*" => :visa # Default to VISA for unknown BINs }, connection_pool: %{ size: 5, max_overflow: 10, timeout: 5_000, checkout_timeout: 30_000 }, monitoring: %{ enabled: true, metrics_interval: 30_000, log_level: :info } }) end @doc """ Gets the enhanced routing configuration for Phase B. """ def get_enhanced_routing_config do Application.get_env(:da_product_app, :enhanced_routing, %{ # Default strategy and policy default_strategy: :bin_range, # :bin_range, :merchant_config, :processing_code, :manual default_policy: :load_balance, # :load_balance, :round_robin, :weighted, :failover # Routing table mapping destinations to connector lists routing_table: %{ visa_network: [:visa_primary, :visa_secondary], mastercard_network: [:mc_primary, :mc_secondary], amex_network: [:amex_primary], discover_network: [:discover_primary], domestic_processor: [:domestic_primary, :domestic_secondary], international_processor: [:intl_primary, :intl_secondary], test_processor: [:test_connector], error_handler: [:fallback_connector] }, # Connector weights for weighted routing connector_weights: %{ visa_primary: 10, visa_secondary: 5, mc_primary: 10, mc_secondary: 5, amex_primary: 8, discover_primary: 6, domestic_primary: 10, domestic_secondary: 3, intl_primary: 8, intl_secondary: 4 }, # Merchant-specific routing configurations merchant_configs: %{ "MERCHANT001" => %{ preferred_connectors: [:visa_primary, :mc_primary], routing_strategy: :weighted, custom_weights: %{visa_primary: 8, mc_primary: 7} }, "MERCHANT002" => %{ preferred_connectors: [:domestic_primary], routing_strategy: :failover, force_domestic: true } }, # Processing code routing processing_code_routing: %{ "000000" => [:domestic_primary, :domestic_secondary], # Purchase "200000" => [:domestic_primary, :domestic_secondary], # Return "010000" => [:visa_primary, :mc_primary], # Cash advance "120000" => [:intl_primary, :intl_secondary] # International }, # Load balancer configuration load_balancer: %{ algorithm: :weighted, # :round_robin, :weighted, :least_connections, :response_time health_check_interval: 30_000, health_check_timeout: 5_000, failure_threshold: 3, recovery_threshold: 2, max_connections_per_connector: 100 }, # Connector configurations for circuit breakers and health monitoring connectors: %{ visa_primary: %{ weight: 10, failure_threshold: 5, recovery_timeout: 30_000, timeout: 5_000, initial_response_time: 100.0 }, visa_secondary: %{ weight: 5, failure_threshold: 3, recovery_timeout: 45_000, timeout: 7_000, initial_response_time: 150.0 }, mc_primary: %{ weight: 10, failure_threshold: 5, recovery_timeout: 30_000, timeout: 5_000, initial_response_time: 110.0 }, mc_secondary: %{ weight: 5, failure_threshold: 3, recovery_timeout: 45_000, timeout: 7_000, initial_response_time: 160.0 }, amex_primary: %{ weight: 8, failure_threshold: 4, recovery_timeout: 35_000, timeout: 6_000, initial_response_time: 120.0 }, discover_primary: %{ weight: 6, failure_threshold: 4, recovery_timeout: 35_000, timeout: 6_000, initial_response_time: 130.0 }, domestic_primary: %{ weight: 10, failure_threshold: 5, recovery_timeout: 25_000, timeout: 4_000, initial_response_time: 80.0 }, domestic_secondary: %{ weight: 3, failure_threshold: 3, recovery_timeout: 40_000, timeout: 6_000, initial_response_time: 140.0 }, intl_primary: %{ weight: 8, failure_threshold: 4, recovery_timeout: 40_000, timeout: 8_000, initial_response_time: 200.0 }, intl_secondary: %{ weight: 4, failure_threshold: 3, recovery_timeout: 60_000, timeout: 10_000, initial_response_time: 250.0 } } }) end @doc """ Gets the connector configuration. """ def get_connector_config do Application.get_env(:da_product_app, :switch_connectors, %{ # Connection pooling pool: %{ size: 10, max_overflow: 20, timeout_ms: 30_000, checkout_timeout_ms: 5_000 }, # Connector-specific settings visa: %{ enabled: true, host: "visa.gateway.example.com", port: 8583, ssl: false, timeout_ms: 30_000, max_retries: 3 }, mastercard: %{ enabled: true, host: "mc.gateway.example.com", port: 8583, ssl: false, timeout_ms: 30_000, max_retries: 3 }, master: %{ enabled: true, host: "master.processor.example.com", port: 8583, ssl: false, timeout_ms: 30_000, max_retries: 3 }, fallback: %{ enabled: true, default_response_code: "96", enable_logging: true } }) end @doc """ Gets the switch-wide configuration. """ def get_switch_config do Application.get_env(:da_product_app, :switch, %{ # Feature toggles features: %{ enhanced_message_handler: true, enhanced_routing: true, connection_pooling: true, circuit_breakers: true, performance_monitoring: true, security_logging: true }, # Performance settings performance: %{ max_concurrent_messages: 1000, message_processing_timeout_ms: 30_000, enable_async_processing: true, queue_max_size: 10_000 }, # Security settings security: %{ enable_audit_logging: true, mask_sensitive_data: true, max_connection_rate: 100, # per minute enable_rate_limiting: true }, # Monitoring and alerting monitoring: %{ enable_metrics: true, metrics_interval_ms: 60_000, enable_health_checks: true, health_check_interval_ms: 30_000, enable_alerts: true } }) end @doc """ Gets environment-specific configuration. """ def get_env_config do env = Application.get_env(:da_product_app, :environment, :dev) case env do :prod -> %{ log_level: :info, debug_enabled: false, strict_validation: true, enable_monitoring: true, enable_alerts: true, log_raw_data: false } :test -> %{ log_level: :warning, debug_enabled: true, strict_validation: true, enable_monitoring: false, enable_alerts: false, log_raw_data: false, mock_connectors: true } :dev -> %{ log_level: :debug, debug_enabled: true, strict_validation: false, enable_monitoring: true, enable_alerts: false, log_raw_data: true, mock_connectors: false } end end @doc """ Determines which message handler to use based on configuration. """ def get_message_handler do # Always use the modern ISO8583BMessageHandler DaProductApp.Switch.ISO8583BMessageHandler end @doc """ Gets the complete switch configuration. """ def get_complete_config do %{ message_handler: get_message_handler_config(), protocol: get_protocol_config(), routing: get_routing_config(), connectors: get_connector_config(), switch: get_switch_config(), environment: get_env_config() } end @doc """ Validates the switch configuration. """ def validate_config do config = get_complete_config() validation_results = [ validate_message_handler_config(config.message_handler), validate_protocol_config(config.protocol), validate_routing_config(config.routing), validate_connector_config(config.connectors) ] case Enum.find(validation_results, fn result -> match?({:error, _}, result) end) do nil -> {:ok, :configuration_valid} error -> error end end @doc """ Reloads configuration from application environment. """ def reload_config do # Notify components about configuration changes :ok = notify_config_change() {:ok, get_complete_config()} end # Private functions defp validate_message_handler_config(%{handler: handler}) when handler in [:iso8583b] do :ok end defp validate_message_handler_config(_), do: {:error, :invalid_message_handler_config} defp validate_protocol_config(%{tcp: %{port: port}}) when is_integer(port) and port > 0 do :ok end defp validate_protocol_config(_), do: {:error, :invalid_protocol_config} defp validate_routing_config(%{router: router}) when router in [:enhanced, :legacy] do :ok end defp validate_routing_config(_), do: {:error, :invalid_routing_config} defp validate_connector_config(%{pool: %{size: size}}) when is_integer(size) and size > 0 do :ok end defp validate_connector_config(_), do: {:error, :invalid_connector_config} defp notify_config_change do # Implementation would notify running processes about config changes # This could use GenServer calls, PubSub, or other notification mechanisms :ok end end