///|
pub(all) struct MySQL {}

///|
pub impl Dialect for MySQL with supports_string_literal_backslash_escape(_self) {
  true
}

///|
pub impl Dialect for MySQL with supports_boolean_literals(_self) {
  true
}

///|
pub impl Dialect for MySQL with supports_filter_during_aggregation(_self) {
  false
}

///|
pub impl Dialect for MySQL with supports_within_after_array_aggregation(_self) {
  false
}

///|
pub impl Dialect for MySQL with requires_column_types_in_create_table(_self) {
  false
}

///|
pub impl Dialect for MySQL with supports_double_quoted_identifiers(_self) {
  false
}

///|
pub impl Dialect for MySQL with supports_if_not_exists(_self) {
  true
}

///|
pub impl Dialect for MySQL with parse_statement(
  _self : MySQL,
  _parser : Parser,
  tokens : ArrayView[Token],
) -> ParserResult[Statement]? raise ParserError {
  match tokens {
    [Keyword(Lock), Keyword(Tables), Identifier(table_name), Semicolon, .. rest] => {
      // MySQL LOCK TABLES statement
      let table = ObjectName::{ parts: [table_name] }
      Some((Statement::LockTables([table]), rest))
    }
    [Keyword(Unlock), Keyword(Tables), Semicolon, .. rest] => {
      // MySQL UNLOCK TABLES statement
      Some((Statement::UnlockTables, rest))
    }
    _ => None  // Fall back to generic parsing
  }
}

///|
pub impl Dialect for MySQL with parse_expr(
  _self : MySQL,
  _tokens : ArrayView[Token],
) -> ParserResult[Expr]? raise ParserError {
  // MySQL DIV operator needs to be parsed in the main parser as it's infix
  // For now, returning None to use the generic parsing
  None
}


///|

test "MySQL SHOW TABLES" {
  let tokens = "SHOW TABLES;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SHOW TABLES;
    ),
  )
}

///|
test "MySQL SHOW COLUMNS FROM table" {
  let tokens = "SHOW COLUMNS FROM users;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SHOW COLUMNS FROM users;
    ),
  )
}

///|
test "MySQL SHOW TABLES LIKE pattern" {
  let tokens = "SHOW TABLES LIKE 'user%';"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SHOW TABLES LIKE 'user%';
    ),
  )
}

///|
test "MySQL with backticks in SHOW" {
  let tokens = "SHOW COLUMNS FROM `table name`;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SHOW COLUMNS FROM `table name`;
    ),
  )
}

///|
test "MySQL LOCK TABLES" {
  let tokens = "LOCK TABLES users;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|LOCK TABLES users;
    ),
  )
}

///|
test "MySQL UNLOCK TABLES" {
  let tokens = "UNLOCK TABLES;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|UNLOCK TABLES;
    ),
  )
}

///|
test "MySQL DIV operator" {
  let tokens = "SELECT 10 DIV 3 FROM test;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print  
  inspect(
    stmt,
    content=(
      #|SELECT
      #|  10  DIV  3
      #|FROM
      #|  test;
    ),
  )
}

///|
test "MySQL SHOW VARIABLES" {
  let tokens = "SHOW VARIABLES;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SHOW VARIABLES;
    ),
  )
}

///|
test "MySQL SHOW GLOBAL STATUS" {
  let tokens = "SHOW GLOBAL STATUS;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SHOW GLOBAL STATUS;
    ),
  )
}

///|
test "MySQL SHOW FULL PROCESSLIST" {
  let tokens = "SHOW FULL PROCESSLIST;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SHOW FULL PROCESSLIST;
    ),
  )
}

///|
test "MySQL SHOW CREATE TABLE" {
  let tokens = "SHOW CREATE TABLE users;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SHOW CREATE TABLE users;
    ),
  )
}

///|
test "MySQL SHOW EXTENDED COLUMNS" {
  let tokens = "SHOW EXTENDED COLUMNS FROM users LIKE 'name%';"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SHOW EXTENDED COLUMNS FROM users LIKE 'name%';
    ),
  )
}

///|
test "MySQL SET session variable" {
  let tokens = "SET SESSION sql_mode = 'STRICT_TRANS_TABLES';"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SET SESSION sql_mode = 'STRICT_TRANS_TABLES';
    ),
  )
}

///|
test "MySQL SET global variable" {
  let tokens = "SET GLOBAL max_connections = 200;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SET GLOBAL max_connections = 200;
    ),
  )
}

///|
test "MySQL SET user variable" {
  let tokens = "SET @counter = 1;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SET @counter = 1;
    ),
  )
}

///|
test "MySQL SET multiple variables" {
  let tokens = "SET @name = 'John', @age = 30, @salary = 50000.50;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SET @name = 'John', @age = 30, @salary = 50000.5;
    ),
  )
}

///|
test "MySQL SET local variable" {
  let tokens = "SET autocommit = 0;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|SET autocommit = 0;
    ),
  )
}

///|
test "MySQL REPLACE INTO statement" {
  let tokens = "REPLACE INTO users (id, name) VALUES (1, 'John');"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|REPLACE INTO users (id, name) VALUES (1, 'John');
    ),
  )
}

///|
test "MySQL REPLACE INTO with multiple values" {
  let tokens = "REPLACE INTO products (id, name, price) VALUES (1, 'Widget', 10.50), (2, 'Gadget', 15.00);"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|REPLACE INTO products (id, name, price) VALUES (1, 'Widget', 10.5), (2, 'Gadget', 15);
    ),
  )
}

///|
test "MySQL INSERT OR REPLACE statement" {
  let tokens = "INSERT OR REPLACE INTO settings (key, value) VALUES ('theme', 'dark');"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|REPLACE INTO settings (key, value) VALUES ('theme', 'dark');
    ),
  )
}

///|
test "MySQL INSERT with ON DUPLICATE KEY UPDATE" {
  let tokens = "INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com') ON DUPLICATE KEY UPDATE name = 'John Updated', email = 'john.new@example.com';"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com') ON DUPLICATE KEY UPDATE name = 'John Updated', email = 'john.new@example.com';
    ),
  )
}

///|
test "MySQL INSERT single assignment ON DUPLICATE KEY UPDATE" {
  let tokens = "INSERT INTO counters (id, count) VALUES (1, 1) ON DUPLICATE KEY UPDATE count = count + 1;"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|INSERT INTO counters (id, count) VALUES (1, 1) ON DUPLICATE KEY UPDATE count = count + 1;
    ),
  )
}

///|
test "MySQL REPLACE with ON DUPLICATE KEY UPDATE" {
  let tokens = "REPLACE INTO settings (setting_key, setting_value) VALUES ('theme', 'dark') ON DUPLICATE KEY UPDATE setting_value = 'light';"
  let stmt = parse_sql(dialect=MySQL::{}, tokens).stmts[0] |> pretty_print
  inspect(
    stmt,
    content=(
      #|REPLACE INTO settings (setting_key, setting_value) VALUES ('theme', 'dark') ON DUPLICATE KEY UPDATE setting_value = 'light';
    ),
  )
}