// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

//! Tests for the `derive_dialect!` macro.

use sqlparser::ast::{
    BinaryOperator, Expr, FunctionArg, FunctionArgExpr, FunctionArguments, LambdaSyntax, Statement,
};
use sqlparser::derive_dialect;
use sqlparser::dialect::{Dialect, GenericDialect, MySqlDialect, PostgreSqlDialect};
use sqlparser::parser::Parser;
use sqlparser::test_utils::{expr_from_projection, only};

#[test]
fn test_method_overrides() {
    derive_dialect!(EnhancedGenericDialect, GenericDialect, overrides = {
        supports_order_by_all = true,
        supports_triple_quoted_string = true,
    });
    let dialect = EnhancedGenericDialect::new();

    // Overridden methods
    assert!(dialect.supports_order_by_all());
    assert!(dialect.supports_triple_quoted_string());

    // Non-overridden retains base behavior
    assert!(!dialect.supports_factorial_operator());

    // Parsing works with the overrides
    let statements = Parser::new(&dialect)
        .try_with_sql("SELECT '''value''' FROM t ORDER BY ALL")
        .unwrap()
        .parse_statements()
        .unwrap();
    assert_eq!(statements.len(), 1);
    assert_eq!(
        statements[0].to_string(),
        "SELECT '''value''' FROM t ORDER BY ALL"
    );
}

#[test]
fn test_preserve_type_id() {
    // Check the override works and the parser recognizes it as the base type
    derive_dialect!(
        PreservedTypeDialect,
        GenericDialect,
        preserve_type_id = true,
        overrides = { supports_order_by_all = true }
    );
    let dialect = PreservedTypeDialect::new();
    let d: &dyn Dialect = &dialect;

    assert!(dialect.supports_order_by_all());
    assert!(d.is::<GenericDialect>());
}

#[test]
fn test_different_base_dialects() {
    derive_dialect!(
        EnhancedMySqlDialect,
        MySqlDialect,
        overrides = { supports_order_by_all = true }
    );
    derive_dialect!(UniquePostgreSqlDialect, PostgreSqlDialect);

    let pg = UniquePostgreSqlDialect::new();
    let mysql = EnhancedMySqlDialect::new();

    // Inherit different base behaviors
    assert!(pg.supports_filter_during_aggregation()); // PostgreSQL feature
    assert!(mysql.supports_string_literal_backslash_escape()); // MySQL feature
    assert!(mysql.supports_order_by_all()); // Override

    // Each has unique TypeId
    let pg_ref: &dyn Dialect = &pg;
    let mysql_ref: &dyn Dialect = &mysql;
    assert!(pg_ref.is::<UniquePostgreSqlDialect>());
    assert!(!pg_ref.is::<PostgreSqlDialect>());
    assert!(mysql_ref.is::<EnhancedMySqlDialect>());
}

#[test]
fn test_identifier_quote_style_overrides() {
    derive_dialect!(
        BacktickGenericDialect,
        GenericDialect,
        overrides = { identifier_quote_style = '`' }
    );
    derive_dialect!(
        AnotherBacktickDialect,
        GenericDialect,
        overrides = { identifier_quote_style = '[' }
    );
    derive_dialect!(
        QuotelessPostgreSqlDialect,
        PostgreSqlDialect,
        preserve_type_id = true,
        overrides = { identifier_quote_style = None }
    );

    // Char literal (auto-wrapped in Some)
    assert_eq!(
        BacktickGenericDialect::new().identifier_quote_style("x"),
        Some('`')
    );
    // Another char literal
    assert_eq!(
        AnotherBacktickDialect::new().identifier_quote_style("x"),
        Some('[')
    );
    // None (overrides PostgreSQL's default '"')
    assert_eq!(
        QuotelessPostgreSqlDialect::new().identifier_quote_style("x"),
        None
    );
}

#[test]
fn test_lambda_keyword_syntax_with_json_arrow_operator() {
    // A custom dialect can opt into the `LAMBDA` keyword spelling of lambda
    // functions without giving up `->` as JSON member access. The two meet in
    // a single expression below: a lambda whose body is a JSON access.
    //
    // PostgreSqlDialect is used only as a convenient base that already gives
    // `->` its JSON meaning; nothing here is specific to PostgreSQL.
    derive_dialect!(
        LambdaPostgreSqlDialect,
        PostgreSqlDialect,
        overrides = { supports_lambda_keyword_syntax = true }
    );
    let dialect = LambdaPostgreSqlDialect::new();

    // Only the keyword spelling is enabled; the arrow spelling stays off.
    assert!(dialect.supports_lambda_keyword_syntax());
    assert!(!dialect.supports_lambda_functions());

    let sql = "SELECT transform(xs, lambda x : (x -> 'a')::INT + 1)";
    let ast = Parser::parse_sql(&dialect, sql).unwrap();
    assert_eq!(sql, ast[0].to_string());

    // Round-tripping alone would not distinguish a JSON access from a nested
    // lambda, since both print as `x -> 'a'`, so check the parsed shape.
    let Statement::Query(query) = &ast[0] else {
        panic!("unexpected statement {}", ast[0]);
    };
    let Expr::Function(func) =
        expr_from_projection(only(&query.body.as_select().unwrap().projection))
    else {
        panic!("expected a function call");
    };
    let FunctionArguments::List(args) = &func.args else {
        panic!("expected an argument list");
    };
    let [_, FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Lambda(lambda)))] = &args.args[..]
    else {
        panic!("expected the second argument to be a lambda");
    };

    // The lambda came from the `LAMBDA` keyword, not from `->`.
    assert_eq!(LambdaSyntax::LambdaKeyword, lambda.syntax);

    // And the `->` in its body is still JSON member access.
    let Expr::BinaryOp {
        left,
        op: BinaryOperator::Plus,
        ..
    } = lambda.body.as_ref()
    else {
        panic!("expected the lambda body to be an addition");
    };
    let Expr::Cast { expr, .. } = left.as_ref() else {
        panic!("expected the left operand to be a cast");
    };
    let Expr::Nested(json_access) = expr.as_ref() else {
        panic!("expected the cast operand to be parenthesized");
    };
    let Expr::BinaryOp { op, .. } = json_access.as_ref() else {
        panic!("expected `->` to stay a binary operator");
    };
    assert_eq!(&BinaryOperator::Arrow, op);
}
