use tonic::transport::Server;
use tonic_reflection::server::Builder as ReflectionBuilder;

use tokio::sync::mpsc;
use crate::indexer::{indexer_task, IndexCommand};

use common::proto::komp_ac::FILE_DESCRIPTOR_SET;
use crate::server::services::{
    TableStructureHandler,
    TableDefinitionService,
    TablesDataService,
    TableScriptService,
    AuthServiceImpl
};
use common::proto::komp_ac::{
    table_structure::table_structure_service_server::TableStructureServiceServer,
    table_definition::table_definition_server::TableDefinitionServer,
    tables_data::tables_data_server::TablesDataServer,
    table_script::table_script_server::TableScriptServer,
    auth::auth_service_server::AuthServiceServer
};
use search::{SearcherService, SearcherServer};

pub async fn run_server(db_pool: sqlx::PgPool) -> Result<(), Box<dyn std::error::Error>> {
    // Initialize JWT for authentication
    crate::auth::logic::jwt::init_jwt()?;

    let addr = "[::1]:50051".parse()?;
    println!("Unified Server listening on {}", addr);

    // 1. Create the MPSC channel for indexer commands
    let (indexer_tx, indexer_rx) = mpsc::channel::<IndexCommand>(100); // Buffer of 100 messages

    // 2. Spawn the background indexer task
    let indexer_pool = db_pool.clone();
    tokio::spawn(indexer_task(indexer_pool, indexer_rx));

    let reflection_service = ReflectionBuilder::configure()
        .register_encoded_file_descriptor_set(FILE_DESCRIPTOR_SET)
        .build_v1()?;

    // Initialize services, passing the indexer sender to the relevant ones
    let table_definition_service = TableDefinitionService { db_pool: db_pool.clone() };
    let tables_data_service = TablesDataService {
        db_pool: db_pool.clone(),
        indexer_tx: indexer_tx.clone(),
    };
    let table_script_service = TableScriptService { db_pool: db_pool.clone() };
    let auth_service = AuthServiceImpl { db_pool: db_pool.clone() };

    // MODIFIED: Instantiate SearcherService with the database pool
    let search_service = SearcherService { pool: db_pool.clone() };

    Server::builder()
        .add_service(TableStructureServiceServer::new(TableStructureHandler { db_pool: db_pool.clone() }))
        .add_service(TableDefinitionServer::new(table_definition_service))
        .add_service(TablesDataServer::new(tables_data_service))
        .add_service(TableScriptServer::new(table_script_service))
        .add_service(AuthServiceServer::new(auth_service))
        .add_service(SearcherServer::new(search_service))
        .add_service(reflection_service)
        .serve(addr)
        .await?;

    Ok(())
}
