use sqruff_lib_core::dialects::Dialect;
use sqruff_lib_core::dialects::init::DialectKind;
use sqruff_lib_core::dialects::syntax::SyntaxKind;
use sqruff_lib_core::helpers::{Config, ToMatchable};
use sqruff_lib_core::parser::grammar::anyof::{AnyNumberOf, one_of, optionally_bracketed};
use sqruff_lib_core::parser::grammar::delimited::Delimited;
use sqruff_lib_core::parser::grammar::sequence::{Bracketed, Sequence};
use sqruff_lib_core::parser::grammar::{Anything, Nothing, Ref};
use sqruff_lib_core::parser::lexer::Matcher;
use sqruff_lib_core::parser::matchable::MatchableTrait;
use sqruff_lib_core::parser::node_matcher::NodeMatcher;
use sqruff_lib_core::parser::parsers::TypedParser;
use sqruff_lib_core::parser::segments::meta::MetaSegment;
use sqruff_lib_core::parser::types::ParseMode;

use crate::sqlite_keywords::{RESERVED_KEYWORDS, UNRESERVED_KEYWORDS};
use sqruff_lib_core::dialects::init::DialectConfig;
use sqruff_lib_core::value::Value;

sqruff_lib_core::dialect_config!(SQLiteDialectConfig {});

pub fn dialect(config: Option<&Value>) -> Dialect {
    // Parse and validate dialect configuration, falling back to defaults on failure
    let _dialect_config: SQLiteDialectConfig = config
        .map(SQLiteDialectConfig::from_value)
        .unwrap_or_default();

    raw_dialect().config(|dialect| dialect.expand())
}

pub fn raw_dialect() -> Dialect {
    let sqlite_dialect = super::ansi::raw_dialect();
    let mut sqlite_dialect = sqlite_dialect;
    sqlite_dialect.name = DialectKind::Sqlite;

    // Add lexer matchers for SQLite blob literals (X'...' or x'...')
    // These must be inserted before single_quote to take precedence
    sqlite_dialect.insert_lexer_matchers(
        vec![Matcher::regex(
            "bytes_single_quote",
            r"[xX]'([^'\\]|\\.)*'",
            SyntaxKind::BytesSingleQuote,
        )],
        "single_quote",
    );

    sqlite_dialect.sets_mut("reserved_keywords").clear();
    sqlite_dialect
        .sets_mut("reserved_keywords")
        .extend(RESERVED_KEYWORDS);
    sqlite_dialect.sets_mut("unreserved_keywords").clear();
    sqlite_dialect
        .sets_mut("unreserved_keywords")
        .extend(UNRESERVED_KEYWORDS);

    // SQLite supports CTEs with DML statements (INSERT, UPDATE, DELETE)
    // since version 3.8.3. We add these to NonWithSelectableGrammar so
    // WithCompoundStatementSegment can use them.
    sqlite_dialect.add([(
        "NonWithSelectableGrammar".into(),
        one_of(vec![
            Ref::new("SetExpressionSegment").to_matchable(),
            optionally_bracketed(vec![Ref::new("SelectStatementSegment").to_matchable()])
                .to_matchable(),
            Ref::new("NonSetSelectableGrammar").to_matchable(),
            Ref::new("UpdateStatementSegment").to_matchable(),
            Ref::new("InsertStatementSegment").to_matchable(),
            Ref::new("DeleteStatementSegment").to_matchable(),
        ])
        .to_matchable()
        .into(),
    )]);

    sqlite_dialect.add([
        // SQLite blob literal segment (X'...' or x'...')
        (
            "BytesQuotedLiteralSegment".into(),
            TypedParser::new(SyntaxKind::BytesSingleQuote, SyntaxKind::BytesQuotedLiteral)
                .to_matchable()
                .into(),
        ),
        // Extend LiteralGrammar to include blob literals
        (
            "LiteralGrammar".into(),
            sqlite_dialect
                .grammar("LiteralGrammar")
                .copy(
                    Some(vec![Ref::new("BytesQuotedLiteralSegment").to_matchable()]),
                    None,
                    None,
                    None,
                    Vec::new(),
                    false,
                )
                .into(),
        ),
        (
            "ColumnConstraintDefaultGrammar".into(),
            Ref::new("ExpressionSegment").to_matchable().into(),
        ),
        (
            "BooleanBinaryOperatorGrammar".into(),
            one_of(vec![
                Ref::new("AndOperatorGrammar").to_matchable(),
                Ref::new("OrOperatorGrammar").to_matchable(),
                Ref::keyword("REGEXP").to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "PrimaryKeyGrammar".into(),
            Sequence::new(vec![
                Ref::keyword("PRIMARY").to_matchable(),
                Ref::keyword("KEY").to_matchable(),
                Sequence::new(vec![Ref::keyword("AUTOINCREMENT").to_matchable()])
                    .config(|config| {
                        config.optional();
                    })
                    .to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "TemporaryTransientGrammar".into(),
            Ref::new("TemporaryGrammar").to_matchable().into(),
        ),
        (
            "DateTimeLiteralGrammar".into(),
            Sequence::new(vec![
                one_of(vec![
                    Ref::keyword("DATE").to_matchable(),
                    Ref::keyword("DATETIME").to_matchable(),
                ])
                .to_matchable(),
                TypedParser::new(SyntaxKind::SingleQuote, SyntaxKind::DateConstructorLiteral)
                    .to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "BaseExpressionElementGrammar".into(),
            one_of(vec![
                Ref::new("LiteralGrammar").to_matchable(),
                Ref::new("BareFunctionSegment").to_matchable(),
                Ref::new("FunctionSegment").to_matchable(),
                Ref::new("ColumnReferenceSegment").to_matchable(),
                Ref::new("ExpressionSegment").to_matchable(),
                Sequence::new(vec![
                    Ref::new("DatatypeSegment").to_matchable(),
                    Ref::new("LiteralGrammar").to_matchable(),
                ])
                .to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "AutoIncrementGrammar".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "CommentClauseSegment".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "IntervalExpressionSegment".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "TimeZoneGrammar".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "FetchClauseSegment".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "TrimParametersGrammar".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "LikeGrammar".into(),
            Sequence::new(vec![Ref::keyword("LIKE").to_matchable()])
                .to_matchable()
                .into(),
        ),
        (
            "OverlapsClauseSegment".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "MLTableExpressionSegment".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "MergeIntoLiteralGrammar".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "SamplingExpressionSegment".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "OrderByClauseTerminators".into(),
            one_of(vec![
                Ref::keyword("LIMIT").to_matchable(),
                Ref::keyword("WINDOW").to_matchable(),
                Ref::new("FrameClauseUnitGrammar").to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "WhereClauseTerminatorGrammar".into(),
            one_of(vec![
                Ref::keyword("LIMIT").to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("GROUP").to_matchable(),
                    Ref::keyword("BY").to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("ORDER").to_matchable(),
                    Ref::keyword("BY").to_matchable(),
                ])
                .to_matchable(),
                Ref::keyword("WINDOW").to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "FromClauseTerminatorGrammar".into(),
            one_of(vec![
                Ref::keyword("WHERE").to_matchable(),
                Ref::keyword("LIMIT").to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("GROUP").to_matchable(),
                    Ref::keyword("BY").to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("ORDER").to_matchable(),
                    Ref::keyword("BY").to_matchable(),
                ])
                .to_matchable(),
                Ref::keyword("WINDOW").to_matchable(),
                Ref::new("SetOperatorSegment").to_matchable(),
                Ref::new("WithNoSchemaBindingClauseSegment").to_matchable(),
                Ref::new("WithDataClauseSegment").to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "GroupByClauseTerminatorGrammar".into(),
            one_of(vec![
                Sequence::new(vec![
                    Ref::keyword("ORDER").to_matchable(),
                    Ref::keyword("BY").to_matchable(),
                ])
                .to_matchable(),
                Ref::keyword("LIMIT").to_matchable(),
                Ref::keyword("HAVING").to_matchable(),
                Ref::keyword("WINDOW").to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "PostFunctionGrammar".into(),
            Sequence::new(vec![
                Ref::new("FilterClauseGrammar").optional().to_matchable(),
                Ref::new("OverClauseSegment").to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "IgnoreRespectNullsGrammar".into(),
            Nothing::new().to_matchable().into(),
        ),
        (
            "SelectClauseTerminatorGrammar".into(),
            one_of(vec![
                Ref::keyword("FROM").to_matchable(),
                Ref::keyword("WHERE").to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("ORDER").to_matchable(),
                    Ref::keyword("BY").to_matchable(),
                ])
                .to_matchable(),
                Ref::keyword("LIMIT").to_matchable(),
                Ref::new("SetOperatorSegment").to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "FunctionContentsGrammar".into(),
            AnyNumberOf::new(vec![
                Ref::new("ExpressionSegment").to_matchable(),
                Sequence::new(vec![
                    Ref::new("ExpressionSegment").to_matchable(),
                    Ref::keyword("AS").to_matchable(),
                    Ref::new("DatatypeSegment").to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::new("TrimParametersGrammar").to_matchable(),
                    Ref::new("ExpressionSegment")
                        .optional()
                        .exclude(Ref::keyword("FROM"))
                        .config(|config| {
                            config.exclude = Ref::keyword("FROM").to_matchable().into();
                        })
                        .to_matchable(),
                    Ref::keyword("FROM").to_matchable(),
                    Ref::new("ExpressionSegment").to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    one_of(vec![
                        Ref::new("DatetimeUnitSegment").to_matchable(),
                        Ref::new("ExpressionSegment").to_matchable(),
                    ])
                    .to_matchable(),
                    Ref::keyword("FROM").to_matchable(),
                    Ref::new("ExpressionSegment").to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("DISTINCT").optional().to_matchable(),
                    one_of(vec![
                        Ref::new("StarSegment").to_matchable(),
                        Delimited::new(vec![
                            Ref::new("FunctionContentsExpressionGrammar").to_matchable(),
                        ])
                        .to_matchable(),
                    ])
                    .to_matchable(),
                ])
                .to_matchable(),
                Ref::new("OrderByClauseSegment").to_matchable(),
                Sequence::new(vec![
                    one_of(vec![
                        Ref::new("QuotedLiteralSegment").to_matchable(),
                        Ref::new("SingleIdentifierGrammar").to_matchable(),
                        Ref::new("ColumnReferenceSegment").to_matchable(),
                    ])
                    .to_matchable(),
                    Ref::keyword("IN").to_matchable(),
                    one_of(vec![
                        Ref::new("QuotedLiteralSegment").to_matchable(),
                        Ref::new("SingleIdentifierGrammar").to_matchable(),
                        Ref::new("ColumnReferenceSegment").to_matchable(),
                    ])
                    .to_matchable(),
                ])
                .to_matchable(),
                Ref::new("IndexColumnDefinitionSegment").to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "Expression_A_Unary_Operator_Grammar".into(),
            one_of(vec![
                Ref::new("SignedSegmentGrammar")
                    .exclude(Sequence::new(vec![
                        Ref::new("QualifiedNumericLiteralSegment").to_matchable(),
                    ]))
                    .config(|config| {
                        config.exclude = Sequence::new(vec![
                            Ref::new("QualifiedNumericLiteralSegment").to_matchable(),
                        ])
                        .to_matchable()
                        .into();
                    })
                    .to_matchable(),
                Ref::new("TildeSegment").to_matchable(),
                Ref::new("NotOperatorGrammar").to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
        (
            "IsClauseGrammar".into(),
            one_of(vec![
                Ref::keyword("NULL").to_matchable(),
                Ref::new("BooleanLiteralGrammar").to_matchable(),
            ])
            .to_matchable()
            .into(),
        ),
    ]);
    sqlite_dialect.add([(
        "SetOperatorSegment".into(),
        NodeMatcher::new(SyntaxKind::SetOperator, |_| {
            one_of(vec![
                Sequence::new(vec![
                    Ref::keyword("UNION").to_matchable(),
                    one_of(vec![
                        Ref::keyword("DISTINCT").to_matchable(),
                        Ref::keyword("ALL").to_matchable(),
                    ])
                    .config(|config| {
                        config.optional();
                    })
                    .to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    one_of(vec![
                        Ref::keyword("INTERSECT").to_matchable(),
                        Ref::keyword("EXCEPT").to_matchable(),
                    ])
                    .to_matchable(),
                    Ref::keyword("ALL").optional().to_matchable(),
                ])
                .to_matchable(),
            ])
            .config(|config| {
                config.exclude = Sequence::new(vec![
                    Ref::keyword("EXCEPT").to_matchable(),
                    Bracketed::new(vec![Anything::new().to_matchable()]).to_matchable(),
                ])
                .to_matchable()
                .into();
            })
            .to_matchable()
        })
        .to_matchable()
        .into(),
    )]);

    sqlite_dialect.replace_grammar(
        "DatatypeSegment",
        one_of(vec![
            Sequence::new(vec![
                Ref::keyword("DOUBLE").to_matchable(),
                Ref::keyword("PRECISION").to_matchable(),
            ])
            .to_matchable(),
            Sequence::new(vec![
                Ref::keyword("UNSIGNED").to_matchable(),
                Ref::keyword("BIG").to_matchable(),
                Ref::keyword("INT").to_matchable(),
            ])
            .to_matchable(),
            Sequence::new(vec![
                one_of(vec![
                    Sequence::new(vec![
                        one_of(vec![
                            Ref::keyword("VARYING").to_matchable(),
                            Ref::keyword("NATIVE").to_matchable(),
                        ])
                        .to_matchable(),
                        one_of(vec![Ref::keyword("CHARACTER").to_matchable()]).to_matchable(),
                    ])
                    .to_matchable(),
                    Ref::new("DatatypeIdentifierSegment").to_matchable(),
                ])
                .to_matchable(),
                Ref::new("BracketedArguments").optional().to_matchable(),
            ])
            .to_matchable(),
        ])
        .to_matchable(),
    );
    sqlite_dialect.add([(
        "TableEndClauseSegment".into(),
        NodeMatcher::new(SyntaxKind::TableEndClauseSegment, |_| {
            Delimited::new(vec![
                Sequence::new(vec![
                    Ref::keyword("WITHOUT").to_matchable(),
                    Ref::keyword("ROWID").to_matchable(),
                ])
                .to_matchable(),
                Ref::keyword("STRICT").to_matchable(),
            ])
            .to_matchable()
        })
        .to_matchable()
        .into(),
    )]);

    sqlite_dialect.replace_grammar(
        "ValuesClauseSegment",
        Sequence::new(vec![
            Ref::keyword("VALUES").to_matchable(),
            Delimited::new(vec![
                Sequence::new(vec![
                    Bracketed::new(vec![
                        Delimited::new(vec![
                            Ref::keyword("DEFAULT").to_matchable(),
                            Ref::new("ExpressionSegment").to_matchable(),
                        ])
                        .to_matchable(),
                    ])
                    .config(|config| {
                        config.parse_mode(ParseMode::Greedy);
                    })
                    .to_matchable(),
                ])
                .to_matchable(),
            ])
            .to_matchable(),
        ])
        .to_matchable(),
    );
    sqlite_dialect.add([
        (
            "IndexColumnDefinitionSegment".into(),
            NodeMatcher::new(SyntaxKind::IndexColumnDefinition, |_| {
                Sequence::new(vec![
                    one_of(vec![
                        Ref::new("SingleIdentifierGrammar").to_matchable(),
                        Ref::new("ExpressionSegment").to_matchable(),
                    ])
                    .to_matchable(),
                    one_of(vec![
                        Ref::keyword("ASC").to_matchable(),
                        Ref::keyword("DESC").to_matchable(),
                    ])
                    .config(|config| {
                        config.optional();
                    })
                    .to_matchable(),
                ])
                .to_matchable()
            })
            .to_matchable()
            .into(),
        ),
        (
            "InsertStatementSegment".into(),
            NodeMatcher::new(SyntaxKind::InsertStatement, |_| {
                Sequence::new(vec![
                    one_of(vec![
                        Sequence::new(vec![
                            Ref::keyword("INSERT").to_matchable(),
                            Sequence::new(vec![
                                Ref::keyword("OR").to_matchable(),
                                one_of(vec![
                                    Ref::keyword("ABORT").to_matchable(),
                                    Ref::keyword("FAIL").to_matchable(),
                                    Ref::keyword("IGNORE").to_matchable(),
                                    Ref::keyword("REPLACE").to_matchable(),
                                    Ref::keyword("ROLLBACK").to_matchable(),
                                ])
                                .to_matchable(),
                            ])
                            .config(|config| {
                                config.optional();
                            })
                            .to_matchable(),
                        ])
                        .to_matchable(),
                        Ref::keyword("REPLACE").to_matchable(),
                    ])
                    .to_matchable(),
                    Ref::keyword("INTO").to_matchable(),
                    Ref::new("TableReferenceSegment").to_matchable(),
                    Ref::new("BracketedColumnReferenceListGrammar")
                        .optional()
                        .to_matchable(),
                    one_of(vec![
                        Ref::new("ValuesClauseSegment").to_matchable(),
                        optionally_bracketed(vec![Ref::new("SelectableGrammar").to_matchable()])
                            .to_matchable(),
                        Ref::new("DefaultValuesGrammar").to_matchable(),
                    ])
                    .to_matchable(),
                    Ref::new("ReturningClauseSegment").optional().to_matchable(),
                ])
                .to_matchable()
            })
            .to_matchable()
            .into(),
        ),
        (
            "DeleteStatementSegment".into(),
            NodeMatcher::new(SyntaxKind::DeleteStatement, |_| {
                Sequence::new(vec![
                    Ref::keyword("DELETE").to_matchable(),
                    Ref::new("FromClauseSegment").to_matchable(),
                    Ref::new("WhereClauseSegment").optional().to_matchable(),
                    Ref::new("ReturningClauseSegment").optional().to_matchable(),
                ])
                .to_matchable()
            })
            .to_matchable()
            .into(),
        ),
        (
            "UpdateStatementSegment".into(),
            NodeMatcher::new(SyntaxKind::UpdateStatement, |_| {
                Sequence::new(vec![
                    Ref::keyword("UPDATE").to_matchable(),
                    Ref::new("TableReferenceSegment").to_matchable(),
                    Ref::new("AliasExpressionSegment")
                        .exclude(Ref::keyword("SET"))
                        .optional()
                        .to_matchable(),
                    Ref::new("SetClauseListSegment").to_matchable(),
                    Ref::new("FromClauseSegment").optional().to_matchable(),
                    Ref::new("WhereClauseSegment").optional().to_matchable(),
                    Ref::new("ReturningClauseSegment").optional().to_matchable(),
                ])
                .to_matchable()
            })
            .to_matchable()
            .into(),
        ),
    ]);

    let column_constraint = sqlite_dialect
        .grammar("ColumnConstraintSegment")
        .match_grammar(&sqlite_dialect)
        .unwrap()
        .copy(
            Some(vec![
                one_of(vec![
                    Ref::keyword("DEFERRABLE").to_matchable(),
                    Sequence::new(vec![
                        Ref::keyword("NOT").to_matchable(),
                        Ref::keyword("DEFERRABLE").to_matchable(),
                    ])
                    .to_matchable(),
                ])
                .config(|config| {
                    config.optional();
                })
                .to_matchable(),
                one_of(vec![
                    Sequence::new(vec![
                        Ref::keyword("INITIALLY").to_matchable(),
                        Ref::keyword("DEFERRED").to_matchable(),
                    ])
                    .to_matchable(),
                    Sequence::new(vec![
                        Ref::keyword("INITIALLY").to_matchable(),
                        Ref::keyword("IMMEDIATE").to_matchable(),
                    ])
                    .to_matchable(),
                ])
                .config(|config| {
                    config.optional();
                })
                .to_matchable(),
            ]),
            None,
            None,
            None,
            Vec::new(),
            false,
        );
    sqlite_dialect.replace_grammar("ColumnConstraintSegment", column_constraint);

    sqlite_dialect.replace_grammar(
        "TableConstraintSegment",
        Sequence::new(vec![
            Sequence::new(vec![
                Ref::keyword("CONSTRAINT").to_matchable(),
                Ref::new("ObjectReferenceSegment").to_matchable(),
            ])
            .config(|config| {
                config.optional();
            })
            .to_matchable(),
            one_of(vec![
                Sequence::new(vec![
                    Ref::keyword("CHECK").to_matchable(),
                    Bracketed::new(vec![Ref::new("ExpressionSegment").to_matchable()])
                        .to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("UNIQUE").to_matchable(),
                    Ref::new("BracketedColumnReferenceListGrammar").to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::new("PrimaryKeyGrammar").to_matchable(),
                    Ref::new("BracketedColumnReferenceListGrammar").to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::new("ForeignKeyGrammar").to_matchable(),
                    Ref::new("BracketedColumnReferenceListGrammar").to_matchable(),
                    Ref::new("ReferenceDefinitionGrammar").to_matchable(),
                ])
                .to_matchable(),
            ])
            .to_matchable(),
            one_of(vec![
                Ref::keyword("DEFERRABLE").to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("NOT").to_matchable(),
                    Ref::keyword("DEFERRABLE").to_matchable(),
                ])
                .to_matchable(),
            ])
            .config(|config| {
                config.optional();
            })
            .to_matchable(),
            one_of(vec![
                Sequence::new(vec![
                    Ref::keyword("INITIALLY").to_matchable(),
                    Ref::keyword("DEFERRED").to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("INITIALLY").to_matchable(),
                    Ref::keyword("IMMEDIATE").to_matchable(),
                ])
                .to_matchable(),
            ])
            .config(|config| {
                config.optional();
            })
            .to_matchable(),
        ])
        .to_matchable(),
    );

    sqlite_dialect.replace_grammar(
        "TransactionStatementSegment",
        Sequence::new(vec![
            one_of(vec![
                Ref::keyword("BEGIN").to_matchable(),
                Ref::keyword("COMMIT").to_matchable(),
                Ref::keyword("ROLLBACK").to_matchable(),
                Ref::keyword("END").to_matchable(),
            ])
            .to_matchable(),
            one_of(vec![Ref::keyword("TRANSACTION").to_matchable()])
                .config(|config| {
                    config.optional();
                })
                .to_matchable(),
            Sequence::new(vec![
                Ref::keyword("TO").to_matchable(),
                Ref::keyword("SAVEPOINT").to_matchable(),
                Ref::new("ObjectReferenceSegment").to_matchable(),
            ])
            .config(|config| {
                config.optional();
            })
            .to_matchable(),
        ])
        .to_matchable(),
    );

    sqlite_dialect.add([(
        "PragmaReferenceSegment".into(),
        NodeMatcher::new(SyntaxKind::PragmaReference, |sqlite_dialect| {
            sqlite_dialect
                .grammar("ObjectReferenceSegment")
                .match_grammar(sqlite_dialect)
                .unwrap()
        })
        .to_matchable()
        .into(),
    )]);

    sqlite_dialect.add([(
        "PragmaStatementSegment".into(),
        NodeMatcher::new(SyntaxKind::PragmaStatement, |_| {
            let pragma_value = one_of(vec![
                Ref::new("LiteralGrammar").to_matchable(),
                Ref::new("BooleanLiteralGrammar").to_matchable(),
                Ref::keyword("YES").to_matchable(),
                Ref::keyword("NO").to_matchable(),
                Ref::keyword("ON").to_matchable(),
                Ref::keyword("OFF").to_matchable(),
                Ref::keyword("NONE").to_matchable(),
                Ref::keyword("FULL").to_matchable(),
                Ref::keyword("INCREMENTAL").to_matchable(),
                Ref::keyword("DELETE").to_matchable(),
                Ref::keyword("TRUNCATE").to_matchable(),
                Ref::keyword("PERSIST").to_matchable(),
                Ref::keyword("MEMORY").to_matchable(),
                Ref::keyword("WAL").to_matchable(),
                Ref::keyword("NORMAL").to_matchable(),
                Ref::keyword("EXCLUSIVE").to_matchable(),
                Ref::keyword("FAST").to_matchable(),
                Ref::keyword("EXTRA").to_matchable(),
                Ref::keyword("DEFAULT").to_matchable(),
                Ref::keyword("FILE").to_matchable(),
                Ref::keyword("PASSIVE").to_matchable(),
                Ref::keyword("RESTART").to_matchable(),
                Ref::keyword("RESET").to_matchable(),
            ]);

            Sequence::new(vec![
                Ref::keyword("PRAGMA").to_matchable(),
                Ref::new("PragmaReferenceSegment").to_matchable(),
                Bracketed::new(vec![pragma_value.clone().to_matchable()])
                    .config(|config| {
                        config.optional();
                    })
                    .to_matchable(),
                Sequence::new(vec![
                    Ref::new("EqualsSegment").to_matchable(),
                    optionally_bracketed(vec![pragma_value.to_matchable()]).to_matchable(),
                ])
                .config(|config| {
                    config.optional();
                })
                .to_matchable(),
            ])
            .to_matchable()
        })
        .to_matchable()
        .into(),
    )]);

    sqlite_dialect.replace_grammar(
        "CreateTriggerStatementSegment",
        Sequence::new(vec![
            Ref::keyword("CREATE").to_matchable(),
            Ref::new("TemporaryGrammar").optional().to_matchable(),
            Ref::keyword("TRIGGER").to_matchable(),
            Ref::new("IfNotExistsGrammar").optional().to_matchable(),
            Ref::new("TriggerReferenceSegment").to_matchable(),
            one_of(vec![
                Ref::keyword("BEFORE").to_matchable(),
                Ref::keyword("AFTER").to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("INSTEAD").to_matchable(),
                    Ref::keyword("OF").to_matchable(),
                ])
                .to_matchable(),
            ])
            .config(|config| {
                config.optional();
            })
            .to_matchable(),
            one_of(vec![
                Ref::keyword("DELETE").to_matchable(),
                Ref::keyword("INSERT").to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("UPDATE").to_matchable(),
                    Sequence::new(vec![
                        Ref::keyword("OF").to_matchable(),
                        Delimited::new(vec![Ref::new("ColumnReferenceSegment").to_matchable()])
                            .to_matchable(),
                    ])
                    .config(|config| {
                        config.optional();
                    })
                    .to_matchable(),
                ])
                .to_matchable(),
            ])
            .to_matchable(),
            Ref::keyword("ON").to_matchable(),
            Ref::new("TableReferenceSegment").to_matchable(),
            Sequence::new(vec![
                Ref::keyword("FOR").to_matchable(),
                Ref::keyword("EACH").to_matchable(),
                Ref::keyword("ROW").to_matchable(),
            ])
            .config(|config| {
                config.optional();
            })
            .to_matchable(),
            Sequence::new(vec![
                Ref::keyword("WHEN").to_matchable(),
                Bracketed::new(vec![Ref::new("ExpressionSegment").to_matchable()]).to_matchable(),
            ])
            .config(|config| {
                config.optional();
            })
            .to_matchable(),
            Ref::keyword("BEGIN").to_matchable(),
            Delimited::new(vec![
                Ref::new("UpdateStatementSegment").to_matchable(),
                Ref::new("InsertStatementSegment").to_matchable(),
                Ref::new("DeleteStatementSegment").to_matchable(),
                Ref::new("SelectableGrammar").to_matchable(),
            ])
            .config(|config| {
                config.delimiter(
                    AnyNumberOf::new(vec![Ref::new("DelimiterGrammar").to_matchable()]).config(
                        |config| {
                            config.min_times = 1;
                        },
                    ),
                );
                config.allow_trailing = true;
            })
            .to_matchable(),
            Ref::keyword("END").to_matchable(),
        ])
        .to_matchable(),
    );
    sqlite_dialect.add([(
        "UnorderedSelectStatementSegment".into(),
        NodeMatcher::new(SyntaxKind::SelectStatement, |_| {
            Sequence::new(vec![
                Ref::new("SelectClauseSegment").to_matchable(),
                MetaSegment::dedent().to_matchable(),
                Ref::new("FromClauseSegment").optional().to_matchable(),
                Ref::new("WhereClauseSegment").optional().to_matchable(),
                Ref::new("GroupByClauseSegment").optional().to_matchable(),
                Ref::new("HavingClauseSegment").optional().to_matchable(),
                Ref::new("OverlapsClauseSegment").optional().to_matchable(),
                Ref::new("NamedWindowSegment").optional().to_matchable(),
            ])
            .to_matchable()
        })
        .to_matchable()
        .into(),
    )]);

    sqlite_dialect.add([(
        "SelectStatementSegment".into(),
        NodeMatcher::new(SyntaxKind::SelectStatement, |sqlite_dialect| {
            sqlite_dialect
                .grammar("UnorderedSelectStatementSegment")
                .match_grammar(sqlite_dialect)
                .unwrap()
                .copy(
                    Some(vec![
                        Ref::new("OrderByClauseSegment").optional().to_matchable(),
                        Ref::new("FetchClauseSegment").optional().to_matchable(),
                        Ref::new("LimitClauseSegment").optional().to_matchable(),
                        Ref::new("NamedWindowSegment").optional().to_matchable(),
                    ]),
                    None,
                    None,
                    None,
                    Vec::new(),
                    false,
                )
        })
        .to_matchable()
        .into(),
    )]);

    sqlite_dialect.replace_grammar(
        "CreateIndexStatementSegment",
        Sequence::new(vec![
            Ref::keyword("CREATE").to_matchable(),
            Ref::keyword("UNIQUE").optional().to_matchable(),
            Ref::keyword("INDEX").to_matchable(),
            Ref::new("IfNotExistsGrammar").optional().to_matchable(),
            Ref::new("IndexReferenceSegment").to_matchable(),
            Ref::keyword("ON").to_matchable(),
            Ref::new("TableReferenceSegment").to_matchable(),
            Sequence::new(vec![
                Bracketed::new(vec![
                    Delimited::new(vec![
                        Ref::new("IndexColumnDefinitionSegment").to_matchable(),
                    ])
                    .to_matchable(),
                ])
                .to_matchable(),
            ])
            .to_matchable(),
            Ref::new("WhereClauseSegment").optional().to_matchable(),
        ])
        .to_matchable(),
    );

    sqlite_dialect.replace_grammar(
        "StatementSegment",
        one_of(vec![
            Ref::new("AlterTableStatementSegment").to_matchable(),
            Ref::new("CreateIndexStatementSegment").to_matchable(),
            Ref::new("CreateTableStatementSegment").to_matchable(),
            Ref::new("CreateTriggerStatementSegment").to_matchable(),
            Ref::new("CreateViewStatementSegment").to_matchable(),
            Ref::new("DeleteStatementSegment").to_matchable(),
            Ref::new("DropIndexStatementSegment").to_matchable(),
            Ref::new("DropTableStatementSegment").to_matchable(),
            Ref::new("DropTriggerStatementSegment").to_matchable(),
            Ref::new("DropViewStatementSegment").to_matchable(),
            Ref::new("ExplainStatementSegment").to_matchable(),
            Ref::new("InsertStatementSegment").to_matchable(),
            Ref::new("PragmaStatementSegment").to_matchable(),
            Ref::new("SelectableGrammar").to_matchable(),
            Ref::new("TransactionStatementSegment").to_matchable(),
            Ref::new("UpdateStatementSegment").to_matchable(),
            Bracketed::new(vec![Ref::new("StatementSegment").to_matchable()]).to_matchable(),
        ])
        .to_matchable(),
    );

    sqlite_dialect.replace_grammar(
        "AlterTableStatementSegment",
        Sequence::new(vec![
            Ref::keyword("ALTER").to_matchable(),
            Ref::keyword("TABLE").to_matchable(),
            Ref::new("TableReferenceSegment").to_matchable(),
            one_of(vec![
                Sequence::new(vec![
                    Ref::keyword("RENAME").to_matchable(),
                    Ref::keyword("TO").to_matchable(),
                    one_of(vec![
                        one_of(vec![
                            Ref::new("ParameterNameSegment").to_matchable(),
                            Ref::new("QuotedIdentifierSegment").to_matchable(),
                        ])
                        .to_matchable(),
                    ])
                    .to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("RENAME").to_matchable(),
                    Ref::keyword("COLUMN").optional().to_matchable(),
                    Ref::new("ColumnReferenceSegment").to_matchable(),
                    Ref::keyword("TO").to_matchable(),
                    Ref::new("ColumnReferenceSegment").to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("ADD").to_matchable(),
                    Ref::keyword("COLUMN").optional().to_matchable(),
                    Ref::new("ColumnDefinitionSegment").to_matchable(),
                ])
                .to_matchable(),
                Sequence::new(vec![
                    Ref::keyword("DROP").to_matchable(),
                    Ref::keyword("COLUMN").optional().to_matchable(),
                    Ref::new("ColumnReferenceSegment").to_matchable(),
                ])
                .to_matchable(),
            ])
            .to_matchable(),
        ])
        .to_matchable(),
    );

    sqlite_dialect.add([(
        "ReturningClauseSegment".into(),
        Sequence::new(vec![
            Ref::keyword("RETURNING").to_matchable(),
            MetaSegment::indent().to_matchable(),
            one_of(vec![
                Ref::new("StarSegment").to_matchable(),
                Delimited::new(vec![
                    Sequence::new(vec![
                        Ref::new("ExpressionSegment").to_matchable(),
                        Ref::new("AsAliasExpressionSegment")
                            .optional()
                            .to_matchable(),
                    ])
                    .to_matchable(),
                ])
                .to_matchable(),
            ])
            .to_matchable(),
            MetaSegment::dedent().to_matchable(),
        ])
        .to_matchable()
        .into(),
    )]);

    sqlite_dialect.add([(
        "AsAliasExpressionSegment".into(),
        NodeMatcher::new(SyntaxKind::AliasExpression, |_| {
            Sequence::new(vec![
                MetaSegment::indent().to_matchable(),
                Ref::keyword("AS").to_matchable(),
                Ref::new("SingleIdentifierGrammar").to_matchable(),
                MetaSegment::dedent().to_matchable(),
            ])
            .to_matchable()
        })
        .to_matchable()
        .into(),
    )]);

    sqlite_dialect
}
