use std::sync::Arc;

use platform_config::format::ConfigLoader;
use platform_config::{load_deployment_mode, PlatformStartup};
use tower_http::cors::CorsLayer;
use tower_http::trace::TraceLayer;
use tracing::{error, info, warn};
use vault_service::api::{create_age_routes, create_router, AgeState};
use vault_service::config::VaultServiceConfig;
use vault_service::service::KmsService;
use vault_service::AgeKeyManager;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // Initialize centralized observability (logging, metrics, health checks)
    let _guard = observability::init_from_env("vault-service", env!("CARGO_PKG_VERSION"))?;

    info!("Starting vault-service (KMS)...");

    // Load deployment mode configuration
    let deployment = load_deployment_mode()?;

    // Check if vault-service is enabled
    if !deployment.is_service_enabled("vault_service")? {
        warn!("⚠ vault-service is DISABLED in deployment-mode.ncl");
        return Ok(());
    }
    info!("✓ vault-service is ENABLED");

    // Initialize platform startup manager
    let startup = PlatformStartup::new(&deployment.config)?;

    // Validate that all dependencies are enabled
    startup.validate_dependencies("vault_service")?;
    info!("✓ All dependencies are enabled");

    // Setup Git repositories (clone/update if needed)
    let (schemas_path, configs_path) = startup.setup_git_repos()?;
    info!(
        "✓ Git repositories ready\n  • Schemas: {:?}\n  • Configs: {:?}",
        schemas_path, configs_path
    );

    // Load configuration using ConfigLoader trait (unified with other services)
    let vault_config = VaultServiceConfig::load()?;
    info!("✓ Vault-service configuration loaded");
    info!("  server.host: {}", vault_config.vault_service.server.host);
    info!("  server.port: {}", vault_config.vault_service.server.port);
    info!(
        "  vault.backend_type: {}",
        vault_config.vault_service.vault.backend_type
    );
    info!(
        "  vault.storage_backend: {:?}",
        vault_config.vault_service.vault.storage_backend
    );
    info!(
        "  vault.server_url: {:?}",
        vault_config.vault_service.vault.server_url
    );
    info!(
        "  vault.mount_point: {:?}",
        vault_config.vault_service.vault.mount_point
    );

    // Verify SecretumVault binary is available (fail fast)
    let secretumvault_binary = std::env::var("HOME")
        .map(|home| format!("{}/.local/bin/svault", home))
        .unwrap_or_else(|_| ".local/bin/svault".to_string());

    if !std::path::Path::new(&secretumvault_binary).exists() {
        error!("SecretumVault binary not found: {}", secretumvault_binary);
        error!(
            "Please install SecretumVault: https://github.com/provisioning/secretumvault/releases"
        );
        return Err(format!(
            "SecretumVault binary required at {} - not found",
            secretumvault_binary
        )
        .into());
    }
    info!(
        "✓ SecretumVault binary verified at {}",
        secretumvault_binary
    );

    // Convert vault config to KMS backend config
    let kms_config = vault_config.to_kms_backend_config()?;
    info!("✓ Configuration validated and converted to KMS backend config");

    // Create KMS service
    let kms_service = KmsService::new(kms_config).await?;
    info!(
        "KMS service initialized with backend: {}",
        kms_service.get_backend_name()
    );

    // Perform initial health check (non-blocking)
    match kms_service.health_check().await {
        Ok(true) => info!("KMS backend health check: PASSED"),
        Ok(false) => {
            warn!("⚠ KMS backend health check: FAILED - backend may not be ready yet");
        }
        Err(e) => {
            warn!(
                "⚠ KMS backend health check error: {} - service will retry on requests",
                e
            );
        }
    }

    let kms_service = Arc::new(kms_service);

    // Initialize Age key manager for SOPS integration
    let vault_url = vault_config
        .vault_service
        .vault
        .server_url
        .clone()
        .unwrap_or_else(|| "http://localhost:8200".to_string());
    let vault_token = vault_config
        .vault_service
        .vault
        .auth_token
        .clone()
        .unwrap_or_else(String::new);

    let age_key_manager = match AgeKeyManager::new(vault_url.clone(), vault_token.clone()) {
        Ok(manager) => {
            info!("✓ Age key manager initialized for SOPS integration");
            manager
        }
        Err(e) => {
            warn!(
                "⚠ Age key manager initialization failed: {}. Continuing without SOPS Age \
                 endpoints.",
                e
            );
            // Create dummy manager - endpoints will exist but operations may fail
            // This prevents service startup failure if SOPS is not being used
            AgeKeyManager::new("http://localhost:8200", "none")
                .unwrap_or_else(|_| panic!("Failed to create Age key manager"))
        }
    };

    let age_state = Arc::new(AgeState {
        key_manager: age_key_manager,
    });

    // Initialize lease store (shared between NATS handler and HTTPS endpoint)
    let lease_store = Arc::new(vault_service::leases::LeaseStore::new());

    // Create main KMS API router
    let kms_router = create_router(kms_service, Arc::clone(&lease_store));

    // Create Age-specific router for SOPS integration
    let age_router = create_age_routes(age_state);

    // Merge routers
    let app = kms_router
        .merge(age_router)
        .layer(CorsLayer::permissive())
        .layer(TraceLayer::new_for_http());

    // Build bind address from config (can be overridden by env var)
    let configured_port = vault_config.vault_service.server.port;
    let configured_host = vault_config.vault_service.server.host.clone();
    let default_bind_addr = format!("{}:{}", configured_host, configured_port);

    let bind_addr = std::env::var("KMS_BIND_ADDR").unwrap_or(default_bind_addr);

    info!("KMS service listening on {}", bind_addr);
    info!("✓ Age key management endpoints available at /api/v1/age/*");

    // Start server
    let listener = tokio::net::TcpListener::bind(&bind_addr).await?;
    axum::serve(listener, app).await?;

    Ok(())
}
