package org.jpos.tcpay.config;

import java.util.Properties;

/**
 * Configuration properties for transaction reversal management
 * Centralizes all reversal-related timing and behavior parameters
 */
public class ReversalConfig {
    
    // Default configuration values
    private static final Properties DEFAULT_PROPERTIES = new Properties();
    
    static {
        // Reversal timing configuration
        DEFAULT_PROPERTIES.setProperty("reversal.stale.transaction.threshold.seconds", "45");
        DEFAULT_PROPERTIES.setProperty("reversal.response.timeout.seconds", "30");
        DEFAULT_PROPERTIES.setProperty("reversal.retry.max.attempts", "3");
        DEFAULT_PROPERTIES.setProperty("reversal.retry.delay.seconds", "60");
        
        // Connection management
        DEFAULT_PROPERTIES.setProperty("connection.recovery.timeout.seconds", "30");
        DEFAULT_PROPERTIES.setProperty("connection.health.check.interval.seconds", "10");
        
        // Cleanup configuration
        DEFAULT_PROPERTIES.setProperty("startup.cleanup.age.threshold.minutes", "5");
        DEFAULT_PROPERTIES.setProperty("scheduled.cleanup.interval.minutes", "15");
        
        // Monitoring and alerting
        DEFAULT_PROPERTIES.setProperty("monitoring.max.pending.reversals", "10");
        DEFAULT_PROPERTIES.setProperty("monitoring.max.temp.age.minutes", "10");
        DEFAULT_PROPERTIES.setProperty("monitoring.max.reversal.rate.threshold", "0.05");
        DEFAULT_PROPERTIES.setProperty("monitoring.health.check.interval.seconds", "60");
        
        // Database connection pool settings for reversal operations
        DEFAULT_PROPERTIES.setProperty("reversal.db.pool.min.size", "2");
        DEFAULT_PROPERTIES.setProperty("reversal.db.pool.max.size", "10");
        DEFAULT_PROPERTIES.setProperty("reversal.db.pool.timeout.seconds", "30");
        
        // Async processing configuration
        DEFAULT_PROPERTIES.setProperty("reversal.thread.pool.size", "2");
        DEFAULT_PROPERTIES.setProperty("reversal.queue.capacity", "100");
        
        // Logging configuration
        DEFAULT_PROPERTIES.setProperty("reversal.logging.level", "INFO");
        DEFAULT_PROPERTIES.setProperty("reversal.audit.enabled", "true");
        DEFAULT_PROPERTIES.setProperty("reversal.metrics.enabled", "true");
    }
    
    private final Properties properties;
    
    /**
     * Create configuration with default values
     */
    public ReversalConfig() {
        this.properties = new Properties(DEFAULT_PROPERTIES);
    }
    
    /**
     * Create configuration with custom properties
     * @param customProperties custom properties to override defaults
     */
    public ReversalConfig(Properties customProperties) {
        this.properties = new Properties(DEFAULT_PROPERTIES);
        if (customProperties != null) {
            this.properties.putAll(customProperties);
        }
    }
    
    // =================== REVERSAL TIMING GETTERS ===================
    
    public int getStaleTransactionThresholdSeconds() {
        return getIntProperty("reversal.stale.transaction.threshold.seconds");
    }
    
    public int getResponseTimeoutSeconds() {
        return getIntProperty("reversal.response.timeout.seconds");
    }
    
    public int getMaxRetryAttempts() {
        return getIntProperty("reversal.retry.max.attempts");
    }
    
    public int getRetryDelaySeconds() {
        return getIntProperty("reversal.retry.delay.seconds");
    }
    
    // =================== CONNECTION MANAGEMENT GETTERS ===================
    
    public int getConnectionRecoveryTimeoutSeconds() {
        return getIntProperty("connection.recovery.timeout.seconds");
    }
    
    public int getConnectionHealthCheckIntervalSeconds() {
        return getIntProperty("connection.health.check.interval.seconds");
    }
    
    // =================== CLEANUP CONFIGURATION GETTERS ===================
    
    public int getStartupCleanupAgeThresholdMinutes() {
        return getIntProperty("startup.cleanup.age.threshold.minutes");
    }
    
    public int getScheduledCleanupIntervalMinutes() {
        return getIntProperty("scheduled.cleanup.interval.minutes");
    }
    
    // =================== MONITORING GETTERS ===================
    
    public int getMaxPendingReversals() {
        return getIntProperty("monitoring.max.pending.reversals");
    }
    
    public int getMaxTempAgeMinutes() {
        return getIntProperty("monitoring.max.temp.age.minutes");
    }
    
    public double getMaxReversalRateThreshold() {
        return getDoubleProperty("monitoring.max.reversal.rate.threshold");
    }
    
    public int getHealthCheckIntervalSeconds() {
        return getIntProperty("monitoring.health.check.interval.seconds");
    }
    
    // =================== DATABASE CONFIGURATION GETTERS ===================
    
    public int getDbPoolMinSize() {
        return getIntProperty("reversal.db.pool.min.size");
    }
    
    public int getDbPoolMaxSize() {
        return getIntProperty("reversal.db.pool.max.size");
    }
    
    public int getDbPoolTimeoutSeconds() {
        return getIntProperty("reversal.db.pool.timeout.seconds");
    }
    
    // =================== ASYNC PROCESSING GETTERS ===================
    
    public int getThreadPoolSize() {
        return getIntProperty("reversal.thread.pool.size");
    }
    
    public int getQueueCapacity() {
        return getIntProperty("reversal.queue.capacity");
    }
    
    // =================== LOGGING GETTERS ===================
    
    public String getLoggingLevel() {
        return getStringProperty("reversal.logging.level");
    }
    
    public boolean isAuditEnabled() {
        return getBooleanProperty("reversal.audit.enabled");
    }
    
    public boolean isMetricsEnabled() {
        return getBooleanProperty("reversal.metrics.enabled");
    }
    
    // =================== PROPERTY SETTERS ===================
    
    public void setProperty(String key, String value) {
        properties.setProperty(key, value);
    }
    
    public void setStaleTransactionThresholdSeconds(int seconds) {
        setProperty("reversal.stale.transaction.threshold.seconds", String.valueOf(seconds));
    }
    
    public void setResponseTimeoutSeconds(int seconds) {
        setProperty("reversal.response.timeout.seconds", String.valueOf(seconds));
    }
    
    public void setMaxRetryAttempts(int attempts) {
        setProperty("reversal.retry.max.attempts", String.valueOf(attempts));
    }
    
    public void setMaxPendingReversals(int maxPending) {
        setProperty("monitoring.max.pending.reversals", String.valueOf(maxPending));
    }
    
    // =================== HELPER METHODS ===================
    
    private String getStringProperty(String key) {
        return properties.getProperty(key);
    }
    
    private int getIntProperty(String key) {
        try {
            return Integer.parseInt(properties.getProperty(key));
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid integer property: " + key + " = " + properties.getProperty(key));
        }
    }
    
    private double getDoubleProperty(String key) {
        try {
            return Double.parseDouble(properties.getProperty(key));
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid double property: " + key + " = " + properties.getProperty(key));
        }
    }
    
    private boolean getBooleanProperty(String key) {
        return Boolean.parseBoolean(properties.getProperty(key));
    }
    
    /**
     * Get all properties as a Properties object
     */
    public Properties getAllProperties() {
        return new Properties(properties);
    }
    
    /**
     * Load configuration from external file
     */
    public void loadFromFile(String configFilePath) {
        try (java.io.InputStream input = new java.io.FileInputStream(configFilePath)) {
            Properties fileProperties = new Properties();
            fileProperties.load(input);
            properties.putAll(fileProperties);
        } catch (Exception e) {
            throw new RuntimeException("Failed to load reversal configuration from: " + configFilePath, e);
        }
    }
    
    /**
     * Load configuration from classpath resource
     */
    public void loadFromResource(String resourcePath) {
        try (java.io.InputStream input = getClass().getClassLoader().getResourceAsStream(resourcePath)) {
            if (input == null) {
                throw new IllegalArgumentException("Resource not found: " + resourcePath);
            }
            Properties resourceProperties = new Properties();
            resourceProperties.load(input);
            properties.putAll(resourceProperties);
        } catch (Exception e) {
            throw new RuntimeException("Failed to load reversal configuration from resource: " + resourcePath, e);
        }
    }
    
    /**
     * Validate configuration values
     */
    public void validate() throws IllegalArgumentException {
        validatePositive("reversal.stale.transaction.threshold.seconds", getStaleTransactionThresholdSeconds());
        validatePositive("reversal.response.timeout.seconds", getResponseTimeoutSeconds());
        validatePositive("reversal.retry.max.attempts", getMaxRetryAttempts());
        validatePositive("reversal.retry.delay.seconds", getRetryDelaySeconds());
        validatePositive("monitoring.max.pending.reversals", getMaxPendingReversals());
        validatePositive("monitoring.max.temp.age.minutes", getMaxTempAgeMinutes());
        
        if (getMaxRetryAttempts() > 10) {
            throw new IllegalArgumentException("Max retry attempts should not exceed 10");
        }
        
        if (getMaxReversalRateThreshold() < 0.0 || getMaxReversalRateThreshold() > 1.0) {
            throw new IllegalArgumentException("Reversal rate threshold must be between 0.0 and 1.0");
        }
    }
    
    private void validatePositive(String propertyName, int value) {
        if (value <= 0) {
            throw new IllegalArgumentException("Property " + propertyName + " must be positive, got: " + value);
        }
    }
    
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("ReversalConfig{\n");
        properties.entrySet().stream()
                .sorted((e1, e2) -> e1.getKey().toString().compareTo(e2.getKey().toString()))
                .forEach(entry -> sb.append("  ").append(entry.getKey()).append(" = ").append(entry.getValue()).append("\n"));
        sb.append("}");
        return sb.toString();
    }
}