//! Provisioning Platform Daemon
//!
//! A thin wrapper around daemon-cli library with provisioning-specific
//! configuration. All core functionality (Nushell execution, config rendering,
//! i18n) is provided by daemon-cli.

mod config;

use std::path::PathBuf;
use std::sync::Arc;

use axum::Router;
use clap::Parser;
use config::ProvisioningDaemonConfigWrapper;
use daemon_cli::{
    api::api_routes,
    core::{DaemonConfig, HierarchicalCache, Result},
    orchestration::{
        AuditOperation, EncryptOperation, InitServsOperation, OperationRegistry, RuntimeOperation,
        ValidaOperation,
    },
    AppState,
};
use tokio::net::TcpListener;
use tracing_subscriber::EnvFilter;

/// Provisioning daemon - Nushell execution and configuration rendering service
#[derive(Parser, Debug)]
#[command(name = "provisioning-daemon")]
#[command(about = "Provisioning platform daemon with Nushell execution and config rendering")]
#[command(version = env!("CARGO_PKG_VERSION"))]
struct Args {
    /// Configuration file path
    #[arg(short, long)]
    config: Option<PathBuf>,

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

    /// Validate configuration and exit
    #[arg(long)]
    validate_config: bool,

    /// Show configuration and exit
    #[arg(long)]
    show_config: bool,
}

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

    // Initialize logging
    let log_level = if args.verbose { "debug" } else { "info" };
    let filter = EnvFilter::new(format!(
        "provisioning_daemon={},tower_http=info,daemon_cli=info",
        log_level
    ));

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

    tracing::info!(
        "Starting Provisioning Daemon v{}",
        env!("CARGO_PKG_VERSION")
    );

    // Load configuration with hierarchical support
    let config_wrapper = if let Some(explicit_path) = args.config {
        // Use explicit path from CLI argument
        ProvisioningDaemonConfigWrapper {
            config_path: explicit_path,
        }
    } else {
        // Use hierarchical loading (env vars or defaults)
        ProvisioningDaemonConfigWrapper::load_from_hierarchy()
    };

    tracing::debug!("Loading configuration from: {}", config_wrapper.path_str());

    // Load configuration using external daemon library
    let config = DaemonConfig::load(Some(config_wrapper.path().clone()))?;

    // Handle special commands
    if args.validate_config {
        config.validate()?;
        println!("✓ Configuration is valid");
        return Ok(());
    }

    if args.show_config {
        config.print();
        return Ok(());
    }

    // Validate configuration
    config.validate()?;
    tracing::info!("Configuration validated: bind={}", config.server.bind);

    // Create cache system
    let cache = HierarchicalCache::new()?;
    let cache_arc = Arc::new(cache);

    // Create operation registry
    let mut registry = OperationRegistry::default();
    registry.register("valida", Arc::new(ValidaOperation::new(cache_arc.clone())));
    registry.register(
        "runtime",
        Arc::new(RuntimeOperation::new(cache_arc.clone())),
    );
    registry.register(
        "encrypt",
        Arc::new(EncryptOperation::new(cache_arc.clone())),
    );
    registry.register(
        "init-servs",
        Arc::new(InitServsOperation::new(cache_arc.clone())),
    );
    registry.register("audit", Arc::new(AuditOperation::new(cache_arc.clone())));

    tracing::info!(
        "✓ Registered {} operations: {}",
        registry.len(),
        registry.list().join(", ")
    );

    // Create app state
    let state = AppState::new(config.clone(), cache_arc, registry);

    // Create router
    let app = Router::new().nest("/api/v1", api_routes(state.clone()));

    // Start server
    let addr = config.bind_addr()?;
    let listener = TcpListener::bind(addr).await?;

    tracing::info!("✓ Provisioning daemon listening on http://{}", addr);
    tracing::info!("API documentation: http://{}/api/v1/health", addr);
    tracing::info!("Config rendering: http://{}/api/v1/render", addr);
    tracing::info!("i18n translation: http://{}/api/v1/translate", addr);

    // Run server
    axum::serve(listener, app).await?;

    Ok(())
}
