//! Debug empty-actual queries: categorize why we produce zero output.

use altimate_core::lineage::column_lineage;
use altimate_core::schema::types::SqlDialect;
use datafusion::sql::sqlparser::dialect::SnowflakeDialect;
use datafusion::sql::sqlparser::parser::Parser;
use serde::Deserialize;
use std::collections::HashMap;
use std::io::BufRead;
use std::path::Path;

#[derive(Deserialize)]
struct Case {
    name: String,
    sql: String,
    schema: serde_json::Value,
    expected: HashMap<String, Vec<String>>,
}

fn schema_from_json(value: &serde_json::Value) -> HashMap<String, serde_json::Value> {
    match value {
        serde_json::Value::Object(map) => map.iter().map(|(k, v)| (k.clone(), v.clone())).collect(),
        _ => HashMap::new(),
    }
}

fn main() {
    let fixture_path = Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("../../tests/fixtures/lineage/snowflake_ground_truth.jsonl");
    let file = std::fs::File::open(&fixture_path).expect("open");
    let reader = std::io::BufReader::with_capacity(1024 * 1024, file);
    let dialect = SqlDialect::Snowflake;
    let sf_dialect = SnowflakeDialect {};

    let mut total_empty = 0u64;
    let mut parse_fail = 0u64;
    let mut has_star = 0u64;
    let mut has_cte = 0u64;
    let mut has_subquery = 0u64;
    let mut has_union = 0u64;
    let mut expected_cols_total = 0u64;

    // SQL pattern analysis
    let mut sql_first_word: HashMap<String, u64> = HashMap::new();

    let mut samples: Vec<(String, String, Vec<String>)> = Vec::new();

    for line in reader.lines() {
        let line = line.unwrap();
        let line = line.trim();
        if line.is_empty() {
            continue;
        }
        let case: Case = match serde_json::from_str(line) {
            Ok(c) => c,
            Err(_) => continue,
        };

        if case.expected.is_empty() {
            continue;
        }

        let schema = schema_from_json(&case.schema);
        let result = match column_lineage(&case.sql, dialect, &schema, None) {
            Ok(r) => r,
            Err(_) => continue,
        };

        if !result.column_dict.is_empty() {
            continue;
        }

        // This is an empty-actual query
        total_empty += 1;
        expected_cols_total += case.expected.len() as u64;

        let sql_upper = case.sql.to_uppercase();
        let first_word = case
            .sql
            .split_whitespace()
            .next()
            .unwrap_or("")
            .to_uppercase();
        *sql_first_word.entry(first_word).or_default() += 1;

        // Check SQL patterns
        if sql_upper.contains("SELECT *") || sql_upper.contains("SELECT\n*") {
            has_star += 1;
        }
        if sql_upper.contains("WITH ") {
            has_cte += 1;
        }
        if sql_upper.contains("UNION") {
            has_union += 1;
        }
        if sql_upper.contains("(SELECT") || sql_upper.contains("( SELECT") {
            has_subquery += 1;
        }

        // Parse check
        if Parser::parse_sql(&sf_dialect, &case.sql).is_err() {
            parse_fail += 1;
        }

        if samples.len() < 8 {
            let sql_prefix: String = case.sql.chars().take(200).collect();
            let exp_keys: Vec<String> = case.expected.keys().cloned().collect();
            samples.push((case.name.clone(), sql_prefix, exp_keys));
        }
    }

    println!("=== Empty Actual Queries ===");
    println!("Total empty actual:   {total_empty}");
    println!("Expected cols total:  {expected_cols_total}");
    println!("Parse failures:       {parse_fail}");
    println!();
    println!("=== SQL Patterns ===");
    println!("Has SELECT *:         {has_star}");
    println!("Has CTE (WITH):       {has_cte}");
    println!("Has UNION:            {has_union}");
    println!("Has subquery:         {has_subquery}");
    println!();
    println!("=== First Word ===");
    let mut words: Vec<_> = sql_first_word.into_iter().collect();
    words.sort_by(|a, b| b.1.cmp(&a.1));
    for (word, count) in &words {
        println!("  {word:<15} {count:>5}");
    }

    println!();
    println!("=== Samples ===");
    for (i, (name, sql, exp_keys)) in samples.iter().enumerate() {
        println!("--- Sample {} ---", i + 1);
        println!("  Name: {name}");
        println!("  Expected: {:?}", exp_keys);
        println!("  SQL: {sql}...");
        println!();
    }
}
