//! Chainfire distributed KVS server

use anyhow::Result;
use chainfire_server::config::ServerConfig;
use clap::Parser;
use metrics_exporter_prometheus::PrometheusBuilder;
use std::path::PathBuf;
use tracing::info;

/// Chainfire distributed Key-Value Store
#[derive(Parser, Debug)]
#[command(name = "chainfire")]
#[command(author, version, about, long_about = None)]
struct Args {
    /// Configuration file path
    #[arg(short, long, default_value = "chainfire.toml")]
    config: PathBuf,

    /// Node ID (overrides config)
    #[arg(long)]
    node_id: Option<u64>,

    /// Data directory (overrides config)
    #[arg(long)]
    data_dir: Option<PathBuf>,

    /// API listen address (overrides config)
    #[arg(long)]
    api_addr: Option<String>,

    /// Raft listen address (overrides config)
    #[arg(long)]
    raft_addr: Option<String>,

    /// Gossip listen address (overrides config)
    #[arg(long)]
    gossip_addr: Option<String>,

    /// Initial cluster members for bootstrap (comma-separated node_id=addr pairs)
    #[arg(long)]
    initial_cluster: Option<String>,

    /// Enable verbose logging
    #[arg(short, long)]
    verbose: bool,

    /// Metrics port for Prometheus scraping
    #[arg(long, default_value = "9091")]
    metrics_port: u16,
}

#[tokio::main]
async fn main() -> Result<()> {
    let args = Args::parse();

    // Initialize logging
    let filter = if args.verbose {
        "chainfire=debug,tower_http=debug"
    } else {
        "chainfire=info"
    };

    tracing_subscriber::fmt()
        .with_env_filter(filter)
        .with_target(true)
        .init();

    info!("Chainfire v{}", env!("CARGO_PKG_VERSION"));

    // Initialize Prometheus metrics exporter
    let metrics_addr = format!("0.0.0.0:{}", args.metrics_port);
    let builder = PrometheusBuilder::new();
    builder
        .with_http_listener(metrics_addr.parse::<std::net::SocketAddr>()?)
        .install()
        .expect("Failed to install Prometheus metrics exporter");

    info!(
        "Prometheus metrics available at http://{}/metrics",
        metrics_addr
    );

    // Register chainfire metrics
    metrics::describe_counter!(
        "chainfire_kv_requests_total",
        "Total number of KV requests by operation type"
    );
    metrics::describe_counter!(
        "chainfire_kv_bytes_read",
        "Total bytes read from KV store"
    );
    metrics::describe_counter!(
        "chainfire_kv_bytes_written",
        "Total bytes written to KV store"
    );
    metrics::describe_histogram!(
        "chainfire_kv_request_duration_seconds",
        "KV request duration in seconds"
    );
    metrics::describe_gauge!(
        "chainfire_raft_term",
        "Current Raft term"
    );
    metrics::describe_gauge!(
        "chainfire_raft_is_leader",
        "Whether this node is the Raft leader (1=yes, 0=no)"
    );
    metrics::describe_counter!(
        "chainfire_watch_events_total",
        "Total number of watch events emitted"
    );

use config::{Config as Cfg, Environment, File, FileFormat};
use toml; // Import toml for serializing defaults

// ... (rest of existing imports)

    // Load configuration using config-rs
    let mut settings = Cfg::builder()
        // Layer 1: Application defaults. Serialize ServerConfig::default() into TOML.
        .add_source(File::from_str(
            toml::to_string(&ServerConfig::default())?.as_str(),
            FileFormat::Toml,
        ))
        // Layer 2: Environment variables (e.g., CHAINFIRE_NODE__ID, CHAINFIRE_NETWORK__API_ADDR)
        .add_source(
            Environment::with_prefix("CHAINFIRE")
                .separator("__") // Use double underscore for nested fields
        );

    // Layer 3: Configuration file (if specified)
    if args.config.exists() {
        info!("Loading config from file: {}", args.config.display());
        settings = settings.add_source(File::from(args.config.as_path()));
    } else {
        info!("Config file not found, using defaults and environment variables.");
    }

    let mut config: ServerConfig = settings
        .build()?
        .try_deserialize()?;

    // Apply command line overrides (Layer 4: highest precedence)
    if let Some(node_id) = args.node_id {
        config.node.id = node_id;
    }
    if let Some(data_dir) = args.data_dir {
        config.storage.data_dir = data_dir;
    }
    if let Some(api_addr) = args.api_addr {
        config.network.api_addr = api_addr.parse()?;
    }
    if let Some(raft_addr) = args.raft_addr {
        config.network.raft_addr = raft_addr.parse()?;
    }
    if let Some(gossip_addr) = args.gossip_addr {
        config.network.gossip_addr = gossip_addr.parse()?;
    }

    info!(node_id = config.node.id, "Starting node");
    info!(api_addr = %config.network.api_addr, "API address");
    info!(raft_addr = %config.network.raft_addr, "Raft address");
    info!(gossip_addr = %config.network.gossip_addr, "Gossip address");

    // Start the server
    let server = chainfire_server::server::Server::new(config).await?;
    server.run().await?;

    Ok(())
}
