//! SQL pretty-printing using polyglot-sql.
//!
//! Note: polyglot-sql's parse/generate functions use deep recursion that can overflow
//! the default 8MB thread stack. Formatting runs on a thread with a larger stack.

use super::dialect_map::to_polyglot_dialect;
use super::types::FormatResult;
use crate::schema::types::SqlDialect;

/// Stack size for formatting threads (32MB).
const FORMAT_THREAD_STACK_SIZE: usize = 32 * 1024 * 1024;

/// Format (pretty-print) a SQL query using the given dialect's conventions.
///
/// Parses the SQL, then regenerates it with the dialect's generator,
/// producing consistently formatted output.
pub fn format_sql(sql: &str, dialect: SqlDialect) -> FormatResult {
    let sql_owned = sql.to_string();
    std::thread::Builder::new()
        .stack_size(FORMAT_THREAD_STACK_SIZE)
        .spawn(move || format_sql_inner(&sql_owned, dialect))
        .unwrap_or_else(|e| {
            panic!("failed to spawn formatting thread: {e}");
        })
        .join()
        .unwrap_or_else(|_| FormatResult {
            original_sql: String::new(),
            formatted_sql: String::new(),
            dialect: dialect.to_string(),
            success: false,
            error: Some("formatting thread panicked".to_string()),
        })
}

/// Inner implementation of format_sql.
fn format_sql_inner(sql: &str, dialect: SqlDialect) -> FormatResult {
    let pg_dialect = to_polyglot_dialect(dialect);

    match polyglot_sql::parse(sql, pg_dialect) {
        Ok(expressions) => {
            let mut formatted_parts = Vec::new();
            for expr in &expressions {
                match polyglot_sql::generate(expr, pg_dialect) {
                    Ok(formatted) => formatted_parts.push(formatted),
                    Err(e) => {
                        return FormatResult {
                            original_sql: sql.to_string(),
                            formatted_sql: String::new(),
                            dialect: dialect.to_string(),
                            success: false,
                            error: Some(format!("Generation error: {e}")),
                        };
                    }
                }
            }
            let formatted_sql = formatted_parts.join(";\n");
            FormatResult {
                original_sql: sql.to_string(),
                formatted_sql,
                dialect: dialect.to_string(),
                success: true,
                error: None,
            }
        }
        Err(e) => FormatResult {
            original_sql: sql.to_string(),
            formatted_sql: String::new(),
            dialect: dialect.to_string(),
            success: false,
            error: Some(format!("Parse error: {e}")),
        },
    }
}
