package com.dexorder.flink.config;

import org.yaml.snakeyaml.Yaml;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * Application configuration loader.
 * Loads config and secrets from YAML files mounted by Kubernetes.
 */
public class AppConfig {
    private final Map<String, Object> config;
    private final Map<String, Object> secrets;

    public AppConfig(String configPath, String secretsPath) throws IOException {
        this.config = loadYaml(configPath);
        Map<String, Object> loadedSecrets;
        try {
            loadedSecrets = loadYaml(secretsPath);
        } catch (IOException e) {
            // Secrets are optional - use empty map if not found
            loadedSecrets = new HashMap<>();
        }
        this.secrets = loadedSecrets;
    }

    private Map<String, Object> loadYaml(String path) throws IOException {
        Yaml yaml = new Yaml();
        try (InputStream inputStream = new FileInputStream(path)) {
            Map<String, Object> data = yaml.load(inputStream);
            return data != null ? data : new HashMap<>();
        } catch (IOException e) {
            throw new IOException("Failed to load YAML from: " + path, e);
        }
    }

    public String getString(String key) {
        return getString(key, null);
    }

    public String getString(String key, String defaultValue) {
        Object value = config.get(key);
        if (value != null) {
            return value.toString();
        }
        value = secrets.get(key);
        return value != null ? value.toString() : defaultValue;
    }

    public int getInt(String key) {
        return getInt(key, 0);
    }

    public int getInt(String key, int defaultValue) {
        Object value = config.get(key);
        if (value == null) {
            value = secrets.get(key);
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        if (value instanceof String) {
            try {
                return Integer.parseInt((String) value);
            } catch (NumberFormatException e) {
                return defaultValue;
            }
        }
        return defaultValue;
    }

    public boolean getBoolean(String key) {
        return getBoolean(key, false);
    }

    public boolean getBoolean(String key, boolean defaultValue) {
        Object value = config.get(key);
        if (value == null) {
            value = secrets.get(key);
        }
        if (value instanceof Boolean) {
            return (Boolean) value;
        }
        if (value instanceof String) {
            return Boolean.parseBoolean((String) value);
        }
        return defaultValue;
    }

    // ZMQ port getters
    public int getMarketDataPubPort() {
        return getInt("zmq_market_data_pub_port", 5558);
    }

    /** Port where Flink's IngestorBroker binds a PULL socket to receive requests from relay PUSH */
    public int getFlinkRequestPullPort() {
        return getInt("zmq_flink_request_pull_port", 5566);
    }

    /** Port where Flink's IngestorBroker binds a ROUTER for ingestor DEALER connections */
    public int getIngestorBrokerPort() {
        return getInt("zmq_ingestor_broker_port", 5567);
    }

    public String getBindAddress() {
        return getString("zmq_bind_address", "tcp://*");
    }

    // Kafka config
    public String getKafkaBootstrapServers() {
        return getString("kafka_bootstrap_servers", "localhost:9092");
    }

    public String getKafkaTickTopic() {
        return getString("kafka_tick_topic", "market-tick");
    }

    /**
     * Comma-separated OHLC period lengths in seconds for realtime bar computation.
     * Default covers common chart periods: 1m, 5m, 15m, 1h, 4h, 1d.
     */
    public int[] getRealtimePeriods() {
        String raw = getString("realtime_periods", "60,300,900,3600,14400,86400");
        String[] parts = raw.split(",");
        int[] periods = new int[parts.length];
        for (int i = 0; i < parts.length; i++) {
            periods[i] = Integer.parseInt(parts[i].trim());
        }
        return periods;
    }

    public String getKafkaOhlcTopic() {
        return getString("kafka_ohlc_topic", "market-ohlc");
    }

    // Notification config:
    // Task managers PUSH notifications to this endpoint (job manager PULL address)
    public String getNotificationPublishEndpoint() {
        return getString("notification_publish_endpoint", "tcp://flink-jobmanager:5561");
    }

    // Job manager binds PULL on this port to receive notifications from task managers
    public int getNotificationPullPort() {
        return getInt("notification_pull_port", 5561);
    }

    // Iceberg config
    public String getIcebergNamespace() {
        return getString("iceberg_namespace", "trading");
    }

    public String getIcebergTablePrefix() {
        return getString("iceberg_table_prefix", "market");
    }
}
