#![allow(dead_code)]

//! TypeDialog AI Configuration Assistant Microservice
//!
//! Provides intelligent configuration assistance through:
//! - Conversational dialog with LLM
//! - RAG-powered example suggestions
//! - Nickel schema understanding
//! - Configuration generation and validation
//!
//! # Running the service
//!
//! ```bash
//! # Start the HTTP server
//! typedialog-ai serve --port 3000
//!
//! # Or run in CLI interactive mode
//! typedialog-ai cli --schema schema.ncl
//! ```

mod api;
mod assistant;
mod backend;
mod cli;
mod llm;
mod storage;
mod web_ui;

use anyhow::Result;
use clap::{Parser, Subcommand};
use std::path::{Path, PathBuf};
use std::sync::Arc;

#[derive(Parser)]
#[command(name = "typedialog-ai")]
#[command(about = "AI-powered configuration assistant backend and microservice for TypeDialog", long_about = None)]
struct Cli {
    #[command(subcommand)]
    command: Option<Commands>,

    /// AI backend configuration file (TOML)
    ///
    /// If provided, uses this file exclusively.
    /// If not provided, searches: ~/.config/typedialog/ai/{TYPEDIALOG_ENV}.toml → ~/.config/typedialog/ai/config.toml → defaults
    #[arg(global = true, short = 'c', long, value_name = "FILE")]
    config: Option<PathBuf>,

    /// Database path
    #[arg(global = true, long, default_value = ".typedialog/ai.db")]
    db_path: String,

    /// SurrealDB namespace
    #[arg(global = true, long, default_value = "default")]
    namespace: String,

    /// SurrealDB database
    #[arg(global = true, long, default_value = "typedialog")]
    database: String,
}

#[derive(Subcommand)]
enum Commands {
    /// Start the HTTP server
    #[command(about = "Start the HTTP API server")]
    Serve {
        /// Server port
        #[arg(short, long, default_value = "3000")]
        port: u16,

        /// Server host
        #[arg(short = 'H', long, default_value = "127.0.0.1")]
        host: String,
    },

    /// Run in CLI interactive mode
    #[command(about = "Interactive CLI mode")]
    Cli {
        /// Nickel schema path
        #[arg(short, long)]
        schema: String,

        /// Conversation ID (resume existing)
        #[arg(long)]
        conversation_id: Option<String>,
    },
}

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize tracing
    tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::from_default_env()
                .add_directive("typedialog_ai=debug".parse()?),
        )
        .init();

    let cli = Cli::parse();

    // Load configuration
    let config_path = cli.config.as_deref();
    let config = typedialog_ai::config::TypeDialogAiConfig::load_with_cli(config_path)
        .map_err(|e| anyhow::anyhow!("Failed to load configuration: {}", e))?;

    if let Some(path) = config_path {
        println!("📋 Using config: {}", path.display());
    }

    match cli.command {
        Some(Commands::Serve { port, host }) => {
            serve_command(
                &host,
                port,
                &cli.db_path,
                &cli.namespace,
                &cli.database,
                config,
            )
            .await?;
        }
        Some(Commands::Cli {
            schema,
            conversation_id,
        }) => {
            cli_command(
                &schema,
                conversation_id,
                &cli.db_path,
                &cli.namespace,
                &cli.database,
                config,
            )
            .await?;
        }
        None => {
            // Default to serve
            serve_command(
                "127.0.0.1",
                3000,
                &cli.db_path,
                &cli.namespace,
                &cli.database,
                config,
            )
            .await?;
        }
    }

    Ok(())
}

async fn serve_command(
    host: &str,
    port: u16,
    db_path: &str,
    namespace: &str,
    database: &str,
    config: typedialog_ai::config::TypeDialogAiConfig,
) -> Result<()> {
    println!("🚀 Starting TypeDialog AI Service on {}:{}", host, port);
    println!(
        "🤖 LLM Provider: {} ({})",
        config.llm.provider, config.llm.model
    );
    println!(
        "🔍 RAG System: {}",
        if config.rag.enabled {
            "enabled"
        } else {
            "disabled"
        }
    );

    // Initialize database
    let client = Arc::new(storage::SurrealDbClient::new(db_path, namespace, database).await?);
    client.initialize().await?;

    println!("✅ Database initialized");
    println!("📡 API listening on http://{}:{}", host, port);
    println!("🌐 Web UI at http://{}:{}/ui", host, port);

    // Create application state
    let app_state = api::AppState {
        db: client,
        assistants: Arc::new(std::sync::Mutex::new(std::collections::HashMap::new())),
        start_time: std::time::Instant::now(),
    };

    // Create router with all routes
    let app = api::create_router(app_state);

    // Parse host and create socket address
    let addr: std::net::SocketAddr = format!("{}:{}", host, port).parse()?;

    // Create listener
    let listener = tokio::net::TcpListener::bind(&addr).await?;

    tracing::info!("Server listening on {}", addr);

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

    Ok(())
}

async fn cli_command(
    schema: &str,
    conversation_id: Option<String>,
    db_path: &str,
    namespace: &str,
    database: &str,
    config: typedialog_ai::config::TypeDialogAiConfig,
) -> Result<()> {
    // Verify schema file exists
    let schema_path = Path::new(schema);
    if !schema_path.exists() {
        anyhow::bail!("Schema file not found: {}", schema);
    }

    println!(
        "🤖 LLM Provider: {} ({})",
        config.llm.provider, config.llm.model
    );
    println!(
        "🔍 RAG System: {}",
        if config.rag.enabled {
            "enabled"
        } else {
            "disabled"
        }
    );

    // Initialize database
    let client = Arc::new(storage::SurrealDbClient::new(db_path, namespace, database).await?);
    client.initialize().await?;

    // Create interactive session
    let mut session = cli::InteractiveSession::new(schema_path, client, conversation_id).await?;

    // Run interactive conversation loop
    session.run().await?;

    Ok(())
}
