package com.openosrs.client.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ClientConfiguration - Manages client settings and configuration.
 * 
 * Handles:
 * - User preferences
 * - Client settings
 * - Plugin configurations
 * - Performance settings
 */
public class ClientConfiguration {
    private static final Logger logger = LoggerFactory.getLogger(ClientConfiguration.class);
    
    private static final String CONFIG_FILE = "modernized-client.properties";
    private static final String DEFAULT_CONFIG_RESOURCE = "/default-config.properties";
    
    private final ConcurrentHashMap<String, String> settings = new ConcurrentHashMap<>();
    private final Properties defaultProperties = new Properties();
    
    public ClientConfiguration() {
        loadDefaults();
    }
    
    /**
     * Load default configuration from resources.
     */
    private void loadDefaults() {
        try (InputStream is = getClass().getResourceAsStream(DEFAULT_CONFIG_RESOURCE)) {
            if (is != null) {
                defaultProperties.load(is);
                logger.debug("Loaded default configuration");
            } else {
                logger.warn("Default configuration not found, using minimal defaults");
                setMinimalDefaults();
            }
        } catch (IOException e) {
            logger.warn("Failed to load default configuration", e);
            setMinimalDefaults();
        }
    }
    
    /**
     * Set minimal default configuration if resources not available.
     */
    private void setMinimalDefaults() {
        defaultProperties.setProperty("client.fps.target", "50");
        defaultProperties.setProperty("client.memory.lowMemoryMode", "false");
        defaultProperties.setProperty("client.debug.enabled", "false");
        defaultProperties.setProperty("client.plugins.enabled", "true");
        defaultProperties.setProperty("client.scripting.enabled", "true");
        defaultProperties.setProperty("network.timeout.ms", "5000");
        defaultProperties.setProperty("network.maxRetries", "3");
        defaultProperties.setProperty("agent.api.asyncTimeout.ms", "1000");
        defaultProperties.setProperty("agent.api.enableStatistics", "true");
    }
    
    /**
     * Load configuration from file and apply defaults.
     */
    public void load() {
        // First, apply all defaults
        for (String key : defaultProperties.stringPropertyNames()) {
            settings.put(key, defaultProperties.getProperty(key));
        }
        
        // Then try to load user configuration
        Path configFile = Paths.get(CONFIG_FILE);
        if (Files.exists(configFile)) {
            try {
                Properties userProps = new Properties();
                userProps.load(Files.newBufferedReader(configFile));
                
                // Override defaults with user settings
                for (String key : userProps.stringPropertyNames()) {
                    settings.put(key, userProps.getProperty(key));
                }
                
                logger.info("Loaded configuration from {}", configFile);
                
            } catch (IOException e) {
                logger.warn("Failed to load configuration from {}, using defaults", configFile, e);
            }
        } else {
            logger.info("No configuration file found, using defaults");
        }
        
        logger.debug("Configuration loaded with {} settings", settings.size());
    }
    
    /**
     * Save current configuration to file.
     */
    public void save() {
        Path configFile = Paths.get(CONFIG_FILE);
        
        try {
            Properties props = new Properties();
            props.putAll(settings);
            props.store(Files.newBufferedWriter(configFile), 
                "Modernized OpenOSRS Client Configuration");
            
            logger.info("Configuration saved to {}", configFile);
            
        } catch (IOException e) {
            logger.error("Failed to save configuration to {}", configFile, e);
        }
    }
    
    // Configuration getters with type conversion
    
    public String getString(String key, String defaultValue) {
        return settings.getOrDefault(key, defaultValue);
    }
    
    public String getString(String key) {
        return settings.get(key);
    }
    
    public int getInt(String key, int defaultValue) {
        try {
            String value = settings.get(key);
            return value != null ? Integer.parseInt(value) : defaultValue;
        } catch (NumberFormatException e) {
            logger.warn("Invalid integer value for {}: {}", key, settings.get(key));
            return defaultValue;
        }
    }
    
    public long getLong(String key, long defaultValue) {
        try {
            String value = settings.get(key);
            return value != null ? Long.parseLong(value) : defaultValue;
        } catch (NumberFormatException e) {
            logger.warn("Invalid long value for {}: {}", key, settings.get(key));
            return defaultValue;
        }
    }
    
    public boolean getBoolean(String key, boolean defaultValue) {
        String value = settings.get(key);
        return value != null ? Boolean.parseBoolean(value) : defaultValue;
    }
    
    public double getDouble(String key, double defaultValue) {
        try {
            String value = settings.get(key);
            return value != null ? Double.parseDouble(value) : defaultValue;
        } catch (NumberFormatException e) {
            logger.warn("Invalid double value for {}: {}", key, settings.get(key));
            return defaultValue;
        }
    }
    
    // Configuration setters
    
    public void setString(String key, String value) {
        if (value != null) {
            settings.put(key, value);
        } else {
            settings.remove(key);
        }
    }
    
    public void setInt(String key, int value) {
        settings.put(key, String.valueOf(value));
    }
    
    public void setLong(String key, long value) {
        settings.put(key, String.valueOf(value));
    }
    
    public void setBoolean(String key, boolean value) {
        settings.put(key, String.valueOf(value));
    }
    
    public void setDouble(String key, double value) {
        settings.put(key, String.valueOf(value));
    }
    
    // Convenience methods for common settings
    
    public int getTargetFPS() {
        return getInt("client.fps.target", 50);
    }
    
    public void setTargetFPS(int fps) {
        setInt("client.fps.target", fps);
    }
    
    public boolean isLowMemoryMode() {
        return getBoolean("client.memory.lowMemoryMode", false);
    }
    
    public void setLowMemoryMode(boolean enabled) {
        setBoolean("client.memory.lowMemoryMode", enabled);
    }
    
    public boolean isDebugEnabled() {
        return getBoolean("client.debug.enabled", false);
    }
    
    public void setDebugEnabled(boolean enabled) {
        setBoolean("client.debug.enabled", enabled);
    }
    
    public boolean arePluginsEnabled() {
        return getBoolean("client.plugins.enabled", true);
    }
    
    public void setPluginsEnabled(boolean enabled) {
        setBoolean("client.plugins.enabled", enabled);
    }
    
    public boolean isScriptingEnabled() {
        return getBoolean("client.scripting.enabled", true);
    }
    
    public void setScriptingEnabled(boolean enabled) {
        setBoolean("client.scripting.enabled", enabled);
    }
    
    public int getNetworkTimeout() {
        return getInt("network.timeout.ms", 5000);
    }
    
    public void setNetworkTimeout(int timeoutMs) {
        setInt("network.timeout.ms", timeoutMs);
    }
    
    public int getNetworkMaxRetries() {
        return getInt("network.maxRetries", 3);
    }
    
    public void setNetworkMaxRetries(int maxRetries) {
        setInt("network.maxRetries", maxRetries);
    }
    
    public int getAgentApiTimeout() {
        return getInt("agent.api.asyncTimeout.ms", 1000);
    }
    
    public void setAgentApiTimeout(int timeoutMs) {
        setInt("agent.api.asyncTimeout.ms", timeoutMs);
    }
    
    public boolean isAgentApiStatisticsEnabled() {
        return getBoolean("agent.api.enableStatistics", true);
    }
    
    public void setAgentApiStatisticsEnabled(boolean enabled) {
        setBoolean("agent.api.enableStatistics", enabled);
    }
}