// Tests for fn_ui::sql_parse / sql_classify (cpp/functions/core/sql_parse).
// Pura: tokeniza SQL multi-statement saltando strings y comentarios, y
// clasifica por keyword inicial.

#define CATCH_CONFIG_MAIN
#include "catch_amalgamated.hpp"

#include "core/sql_parse.h"

using fn_ui::sql_parse;
using fn_ui::sql_classify;
using fn_ui::SqlStmtKind;

TEST_CASE("sql_parse classifies common statements") {
    auto stmts = sql_parse("SELECT * FROM t; INSERT INTO t VALUES (1);");
    REQUIRE(stmts.size() == 2);
    REQUIRE(stmts[0].kind == SqlStmtKind::Select);
    REQUIRE(stmts[1].kind == SqlStmtKind::Insert);
}

TEST_CASE("sql_parse handles strings and comments") {
    auto stmts = sql_parse("-- comment\nSELECT 'a;b' FROM t; /* x */ DELETE FROM t;");
    REQUIRE(stmts.size() == 2);
    REQUIRE(stmts[0].kind == SqlStmtKind::Select);
    REQUIRE(stmts[1].kind == SqlStmtKind::Delete);
}

TEST_CASE("sql_parse trims and ignores empty") {
    auto stmts = sql_parse(";  ;  SELECT 1;;");
    REQUIRE(stmts.size() == 1);
    REQUIRE(stmts[0].kind == SqlStmtKind::Select);
}

TEST_CASE("sql_parse: ddl and dcl keywords") {
    auto stmts = sql_parse("CREATE TABLE t(a); DROP TABLE t; ALTER TABLE t ADD b; UPDATE t SET a=1;");
    REQUIRE(stmts.size() == 4);
    REQUIRE(stmts[0].kind == SqlStmtKind::Create);
    REQUIRE(stmts[1].kind == SqlStmtKind::Drop);
    REQUIRE(stmts[2].kind == SqlStmtKind::Alter);
    REQUIRE(stmts[3].kind == SqlStmtKind::Update);
}

TEST_CASE("sql_parse: pragma and explain") {
    auto stmts = sql_parse("PRAGMA foreign_keys = ON; EXPLAIN SELECT 1;");
    REQUIRE(stmts.size() == 2);
    REQUIRE(stmts[0].kind == SqlStmtKind::Pragma);
    REQUIRE(stmts[1].kind == SqlStmtKind::Explain);
}

TEST_CASE("sql_parse: WITH clasifica como Select") {
    auto stmts = sql_parse("WITH x AS (SELECT 1) SELECT * FROM x;");
    REQUIRE(stmts.size() == 1);
    REQUIRE(stmts[0].kind == SqlStmtKind::Select);
}

TEST_CASE("sql_parse: case-insensitive y trim") {
    auto stmts = sql_parse("  select 1;\n   INSERT  INTO  t  VALUES (2);");
    REQUIRE(stmts.size() == 2);
    REQUIRE(stmts[0].kind == SqlStmtKind::Select);
    REQUIRE(stmts[1].kind == SqlStmtKind::Insert);
}

TEST_CASE("sql_parse: line tracking") {
    auto stmts = sql_parse("\n\nSELECT 1;\n-- skip\nDELETE FROM t;\n");
    REQUIRE(stmts.size() == 2);
    REQUIRE(stmts[0].line == 3);
    REQUIRE(stmts[1].line == 5);
}

TEST_CASE("sql_parse: ultimo statement sin ;") {
    auto stmts = sql_parse("SELECT 1");
    REQUIRE(stmts.size() == 1);
    REQUIRE(stmts[0].kind == SqlStmtKind::Select);
}

TEST_CASE("sql_classify: standalone") {
    REQUIRE(sql_classify("SELECT 1") == SqlStmtKind::Select);
    REQUIRE(sql_classify("garbage")   == SqlStmtKind::Unknown);
    REQUIRE(sql_classify("")          == SqlStmtKind::Unknown);
    REQUIRE(sql_classify("/* c */ DELETE FROM t") == SqlStmtKind::Delete);
}

TEST_CASE("sql_parse: ; dentro de string no separa") {
    auto stmts = sql_parse("SELECT 'a;b;c' FROM t;");
    REQUIRE(stmts.size() == 1);
    REQUIRE(stmts[0].kind == SqlStmtKind::Select);
}

TEST_CASE("sql_parse: backtick identifier") {
    auto stmts = sql_parse("SELECT * FROM `weird;name`;");
    REQUIRE(stmts.size() == 1);
    REQUIRE(stmts[0].kind == SqlStmtKind::Select);
}
