// Copyright 2023-2026 GrepTime Inc.
//
// This file is part of the GreptimeDB Enterprise Edition and is licensed under
// the GreptimeDB Enterprise License. You may not use this file except in
// compliance with that license. A copy of the license is available at the root
// of this repository in the file LICENSE-ENTERPRISE.
//
// Unless required by applicable law or agreed to in writing, this software is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied.

use snafu::{ResultExt, ensure};
use sqlparser::ast::Ident;
use sqlparser::parser::Parser;
use sqlparser::tokenizer::Token;

use crate::error::{self, DuplicateClauseSnafu, InvalidSqlSnafu, Result};
use crate::parser::ParserContext;
use crate::parsers::create_parser::trigger::{ANNOTATIONS, LABELS, NOTIFY, ON};
use crate::statements::OptionMap;
use crate::statements::alter::trigger::{
    AlterTrigger, AlterTriggerOperation, AnnotationChange, AnnotationOperations, LabelChange,
    LabelOperations, NotifyChannelChange, NotifyChannelOperations,
};
use crate::statements::create::trigger::NotifyChannel;
use crate::statements::statement::Statement;

/// Some keywords about trigger.
pub const RENAME: &str = "RENAME";
pub const TO: &str = "TO";
pub const SET: &str = "SET";
pub const ADD: &str = "ADD";
pub const MODIFY: &str = "MODIFY";
pub const DROP: &str = "DROP";

impl<'a> ParserContext<'a> {
    /// Parses an `ALTER TRIGGER` statement.
    ///
    /// ```sql
    /// ALTER TRIGGER <trigger_name>
    ///         [alter_option [alter_option] ...]
    ///
    /// alter_option: {
    ///         RENAME TO <new_trigger_name>
    ///         | ON (<query_expression>) EVERY <interval_expression>
    ///         | [SET] LABELS (<label_name>=<label_val>, ...)
    ///         | ADD LABELS (<label_name>=<label_val>, ...)
    ///         | MODIFY LABELS (<label_name>=<label_val>, ...)
    ///         | DROP LABELS (<label_name1>, <label_name2>, ...)
    ///         | [SET] ANNOTATIONS (<annotation_name>=<annotation_val>, ...)
    ///         | ADD ANNOTATIONS (<annotation_name>=<annotation_val>, ...)
    ///         | MODIFY ANNOTATIONS (<annotation_name>=<annotation_val>, ...)
    ///         | DROP ANNOTATIONS (<annotation_name1>, <annotation_name2>, ...)
    ///         | [SET] NOTIFY(
    ///                 WEBHOOK <notify_name1> URL '<url1>' [WITH (<parameter1>=<value1>, ...)],
    ///                 WEBHOOK <notify_name2> URL '<url2>' [WITH (<parameter2>=<value2>, ...)]
    ///         )
    ///         | ADD NOTIFY(
    ///                 WEBHOOK <notify_name1> URL '<url1>' [WITH (<parameter1>=<value1>, ...)],
    ///                 WEBHOOK <notify_name2> URL '<url2>' [WITH (<parameter2>=<value2>, ...)]
    ///         )
    ///         | DROP NOTIFY (<notify_name1>, <notify_name2>)
    /// }
    /// ```
    pub(super) fn parse_alter_trigger(&mut self) -> Result<Statement> {
        let trigger_name = self.intern_parse_table_name()?;

        let mut new_trigger_name = None;
        let mut trigger_on = None;
        let mut label_ops = None;
        let mut annotation_ops = None;
        let mut notify_ops = None;

        loop {
            let next_token = self.parser.peek_token();
            match next_token.token {
                Token::Word(w) if w.value.eq_ignore_ascii_case(RENAME) => {
                    self.parser.next_token();
                    let name = self.parse_rename_to(true)?;
                    let name = Self::canonicalize_identifier(name);
                    ensure!(
                        new_trigger_name.is_none(),
                        DuplicateClauseSnafu {
                            clause: "RENAME TO"
                        }
                    );
                    new_trigger_name.replace(name.value);
                }
                Token::Word(w) if w.value.eq_ignore_ascii_case(ON) => {
                    self.parser.next_token();
                    let new_trigger_on = self.parse_trigger_on(true)?;
                    ensure!(trigger_on.is_none(), DuplicateClauseSnafu { clause: ON });
                    trigger_on.replace(new_trigger_on);
                }
                Token::Word(w) if w.value.eq_ignore_ascii_case(LABELS) => {
                    self.parser.next_token();
                    let labels = self.parse_trigger_labels(true)?;
                    apply_label_replacement(&mut label_ops, labels)?;
                }
                Token::Word(w) if w.value.eq_ignore_ascii_case(ANNOTATIONS) => {
                    self.parser.next_token();
                    let annotations = self.parse_trigger_annotations(true)?;
                    apply_annotation_replacement(&mut annotation_ops, annotations)?;
                }
                Token::Word(w) if w.value.eq_ignore_ascii_case(NOTIFY) => {
                    self.parser.next_token();
                    let channels = self.parse_trigger_notify(true)?;
                    apply_notify_replacement(&mut notify_ops, channels)?;
                }
                Token::Word(w) if w.value.eq_ignore_ascii_case(SET) => {
                    self.parser.next_token();
                    let next_token = self.parser.peek_token();
                    match next_token.token {
                        Token::Word(w) if w.value.eq_ignore_ascii_case(LABELS) => {
                            self.parser.next_token();
                            let labels = self.parse_trigger_labels(true)?;
                            apply_label_replacement(&mut label_ops, labels)?;
                        }
                        Token::Word(w) if w.value.eq_ignore_ascii_case(ANNOTATIONS) => {
                            self.parser.next_token();
                            let annotations = self.parse_trigger_annotations(true)?;
                            apply_annotation_replacement(&mut annotation_ops, annotations)?;
                        }
                        Token::Word(w) if w.value.eq_ignore_ascii_case(NOTIFY) => {
                            self.parser.next_token();
                            let channels = self.parse_trigger_notify(true)?;
                            apply_notify_replacement(&mut notify_ops, channels)?;
                        }
                        _ => {
                            return self.expected(
                                "`LABELS`, `ANNOTATIONS` or `NOTIFY` keyword after `SET`",
                                next_token,
                            );
                        }
                    }
                }
                Token::Word(w) if w.value.eq_ignore_ascii_case(ADD) => {
                    self.parser.next_token();
                    let next_token = self.parser.peek_token();
                    match next_token.token {
                        Token::Word(w) if w.value.eq_ignore_ascii_case(LABELS) => {
                            self.parser.next_token();
                            let labels = self.parse_trigger_labels(true)?;
                            apply_label_change(&mut label_ops, LabelChange::Add(labels))?;
                        }
                        Token::Word(w) if w.value.eq_ignore_ascii_case(ANNOTATIONS) => {
                            self.parser.next_token();
                            let annotations = self.parse_trigger_annotations(true)?;
                            apply_annotation_change(
                                &mut annotation_ops,
                                AnnotationChange::Add(annotations),
                            )?;
                        }
                        Token::Word(w) if w.value.eq_ignore_ascii_case(NOTIFY) => {
                            self.parser.next_token();
                            let channels = self.parse_trigger_notify(true)?;
                            apply_notify_change(
                                &mut notify_ops,
                                NotifyChannelChange::Add(channels),
                            )?;
                        }
                        _ => {
                            return self.expected(
                                "`LABELS`, `ANNOTATIONS` or `NOTIFY` keyword after `ADD`",
                                next_token,
                            );
                        }
                    }
                }
                Token::Word(w) if w.value.eq_ignore_ascii_case(MODIFY) => {
                    self.parser.next_token();
                    let next_token = self.parser.peek_token();
                    match next_token.token {
                        Token::Word(w) if w.value.eq_ignore_ascii_case(LABELS) => {
                            self.parser.next_token();
                            let labels = self.parse_trigger_labels(true)?;
                            apply_label_change(&mut label_ops, LabelChange::Modify(labels))?;
                        }
                        Token::Word(w) if w.value.eq_ignore_ascii_case(ANNOTATIONS) => {
                            self.parser.next_token();
                            let annotations = self.parse_trigger_annotations(true)?;
                            apply_annotation_change(
                                &mut annotation_ops,
                                AnnotationChange::Modify(annotations),
                            )?;
                        }
                        _ => {
                            return self.expected(
                                "`LABELS` or `ANNOTATIONS` keyword after `MODIFY`",
                                next_token,
                            );
                        }
                    }
                }
                Token::Word(w) if w.value.eq_ignore_ascii_case(DROP) => {
                    self.parser.next_token();
                    let next_token = self.parser.peek_token();
                    match next_token.token {
                        Token::Word(w) if w.value.eq_ignore_ascii_case(LABELS) => {
                            self.parser.next_token();
                            let names = self.parse_trigger_label_names(true)?;
                            apply_label_change(&mut label_ops, LabelChange::Drop(names))?;
                        }
                        Token::Word(w) if w.value.eq_ignore_ascii_case(ANNOTATIONS) => {
                            self.parser.next_token();
                            let names = self.parse_trigger_annotation_names(true)?;
                            apply_annotation_change(
                                &mut annotation_ops,
                                AnnotationChange::Drop(names),
                            )?;
                        }
                        Token::Word(w) if w.value.eq_ignore_ascii_case(NOTIFY) => {
                            self.parser.next_token();
                            let channels = self.parse_trigger_notify_names(true)?;
                            apply_notify_change(
                                &mut notify_ops,
                                NotifyChannelChange::Drop(channels),
                            )?;
                        }
                        _ => {
                            return self.expected(
                                "`LABELS`, `ANNOTATIONS` or `NOTIFY` keyword after `DROP`",
                                next_token,
                            );
                        }
                    }
                }
                Token::EOF => break,
                _ => {
                    return self.expected(
                        "`ON` or `SET` or `ADD` or `MODIFY` or `DROP` keyword",
                        next_token,
                    );
                }
            }
        }

        if new_trigger_name.is_none()
            && trigger_on.is_none()
            && label_ops.is_none()
            && annotation_ops.is_none()
            && notify_ops.is_none()
        {
            return self.expected("alter option", self.parser.peek_token());
        }

        let operation = AlterTriggerOperation {
            rename: new_trigger_name,
            trigger_on,
            label_operations: label_ops,
            annotation_operations: annotation_ops,
            notify_channel_operations: notify_ops,
        };

        let alter_trigger = AlterTrigger {
            trigger_name,
            operation,
        };
        Ok(Statement::AlterTrigger(alter_trigger))
    }

    /// The SQL format as follows:
    ///
    /// ```sql
    /// RENAME TO <new_trigger_name>
    /// ```
    ///
    /// ## Parameters
    ///
    /// - `is_first_keyword_matched`: indicates whether the first keyword `RENAME`
    ///     has been matched.
    fn parse_rename_to(&mut self, is_first_keyword_matched: bool) -> Result<Ident> {
        if !is_first_keyword_matched {
            if let Token::Word(w) = self.parser.peek_token().token
                && w.value.eq_ignore_ascii_case(RENAME)
            {
                self.parser.next_token();
            } else {
                return self.expected("`RENAME` keyword", self.parser.peek_token());
            }
        }

        let next_token = self.parser.peek_token();

        match next_token.token {
            Token::Word(w) if w.value.eq_ignore_ascii_case(TO) => {
                self.parser.next_token();
                self.parser.parse_identifier().context(error::SyntaxSnafu)
            }
            _ => self.expected("`TO` keyword after `RENAME`", next_token),
        }
    }

    /// The SQL format as follows:
    ///
    /// ```sql
    /// LABELS (key1, key2)
    /// ```
    ///
    /// ## Parameters
    ///
    /// - `is_first_keyword_matched`: indicates whether the first keyword `LABELS`
    ///     has been matched.
    fn parse_trigger_label_names(&mut self, is_first_keyword_matched: bool) -> Result<Vec<String>> {
        if !is_first_keyword_matched {
            if let Token::Word(w) = self.parser.peek_token().token
                && w.value.eq_ignore_ascii_case(LABELS)
            {
                self.parser.next_token();
            } else {
                return self.expected("`LABELS` keyword", self.parser.peek_token());
            }
        }

        if let Token::LParen = self.parser.peek_token().token {
            self.parser.next_token();
        } else {
            return self.expected("`(` after `LABELS`", self.parser.peek_token());
        }

        let label_names = self
            .parser
            .parse_comma_separated0(Parser::parse_identifier, Token::RParen)
            .context(error::SyntaxSnafu)?
            .into_iter()
            .map(|ident| ident.value.to_lowercase())
            .collect::<Vec<_>>();

        self.parser
            .expect_token(&Token::RParen)
            .context(error::SyntaxSnafu)?;

        Ok(label_names)
    }

    /// The SQL format as follows:
    ///
    /// ```sql
    /// ANNOTATIONS (key1, key2)
    /// ```
    ///
    /// ## Parameters
    ///
    /// - `is_first_keyword_matched`: indicates whether the first keyword `ANNOTATIONS`
    ///     has been matched.
    fn parse_trigger_annotation_names(
        &mut self,
        is_first_keyword_matched: bool,
    ) -> Result<Vec<String>> {
        if !is_first_keyword_matched {
            if let Token::Word(w) = self.parser.peek_token().token
                && w.value.eq_ignore_ascii_case(ANNOTATIONS)
            {
                self.parser.next_token();
            } else {
                return self.expected("`ANNOTATIONS` keyword", self.parser.peek_token());
            }
        }

        if let Token::LParen = self.parser.peek_token().token {
            self.parser.next_token();
        } else {
            return self.expected("`(` after `ANNOTATIONS`", self.parser.peek_token());
        }

        let annotation_names = self
            .parser
            .parse_comma_separated0(Parser::parse_identifier, Token::RParen)
            .context(error::SyntaxSnafu)?
            .into_iter()
            .map(|ident| ident.value.to_lowercase())
            .collect::<Vec<_>>();

        self.parser
            .expect_token(&Token::RParen)
            .context(error::SyntaxSnafu)?;

        Ok(annotation_names)
    }

    /// The SQL format as follows:
    ///
    /// ```sql
    /// NOTIFY (key1, key2)
    /// ```
    ///
    /// ## Parameters
    ///
    /// - `is_first_keyword_matched`: indicates whether the first keyword `NOTIFY`
    ///     has been matched.
    fn parse_trigger_notify_names(
        &mut self,
        is_first_keyword_matched: bool,
    ) -> Result<Vec<String>> {
        if !is_first_keyword_matched {
            if let Token::Word(w) = self.parser.peek_token().token
                && w.value.eq_ignore_ascii_case(NOTIFY)
            {
                self.parser.next_token();
            } else {
                return self.expected("`NOTIFY` keyword", self.parser.peek_token());
            }
        }

        if let Token::LParen = self.parser.peek_token().token {
            self.parser.next_token();
        } else {
            return self.expected("`(` after `NOTIFY`", self.parser.peek_token());
        }

        let notify_names = self
            .parser
            .parse_comma_separated0(Parser::parse_identifier, Token::RParen)
            .context(error::SyntaxSnafu)?
            .into_iter()
            .map(|ident| ident.value.to_lowercase())
            .collect::<Vec<_>>();

        self.parser
            .expect_token(&Token::RParen)
            .context(error::SyntaxSnafu)?;

        Ok(notify_names)
    }
}

fn apply_label_replacement(
    label_ops: &mut Option<LabelOperations>,
    labels: OptionMap,
) -> Result<()> {
    match label_ops {
        Some(LabelOperations::ReplaceAll(_)) => DuplicateClauseSnafu {
            clause: "SET LABELS",
        }
        .fail(),
        Some(LabelOperations::PartialChanges(_)) => InvalidSqlSnafu {
            msg: "SET LABELS cannot be used with ADD/MODIFY/DROP LABELS",
        }
        .fail(),
        None => {
            *label_ops = Some(LabelOperations::ReplaceAll(labels));
            Ok(())
        }
    }
}

fn apply_annotation_replacement(
    annotation_ops: &mut Option<AnnotationOperations>,
    annotations: OptionMap,
) -> Result<()> {
    match annotation_ops {
        Some(AnnotationOperations::ReplaceAll(_)) => DuplicateClauseSnafu {
            clause: "SET ANNOTATIONS",
        }
        .fail(),
        Some(AnnotationOperations::PartialChanges(_)) => InvalidSqlSnafu {
            msg: "SET ANNOTATIONS cannot be used with ADD/MODIFY/DROP ANNOTATIONS",
        }
        .fail(),
        None => {
            *annotation_ops = Some(AnnotationOperations::ReplaceAll(annotations));
            Ok(())
        }
    }
}

fn apply_notify_replacement(
    notify_channel_ops: &mut Option<NotifyChannelOperations>,
    channels: Vec<NotifyChannel>,
) -> Result<()> {
    match notify_channel_ops {
        Some(NotifyChannelOperations::ReplaceAll(_)) => DuplicateClauseSnafu {
            clause: "SET NOTIFY",
        }
        .fail(),
        Some(NotifyChannelOperations::PartialChanges(_)) => InvalidSqlSnafu {
            msg: "SET NOTIFY cannot be used with ADD/DROP NOTIFY",
        }
        .fail(),
        None => {
            *notify_channel_ops = Some(NotifyChannelOperations::ReplaceAll(channels));
            Ok(())
        }
    }
}

fn apply_label_change(
    label_ops: &mut Option<LabelOperations>,
    label_change: LabelChange,
) -> Result<()> {
    match label_ops {
        Some(LabelOperations::ReplaceAll(_)) => InvalidSqlSnafu {
            msg: "SET LABELS cannot be used with ADD/MODIFY/DROP LABELS",
        }
        .fail(),
        Some(LabelOperations::PartialChanges(label_changes)) => {
            label_changes.push(label_change);
            Ok(())
        }
        None => {
            *label_ops = Some(LabelOperations::PartialChanges(vec![label_change]));
            Ok(())
        }
    }
}

fn apply_annotation_change(
    annotation_ops: &mut Option<AnnotationOperations>,
    annotation_change: AnnotationChange,
) -> Result<()> {
    match annotation_ops {
        Some(AnnotationOperations::ReplaceAll(_)) => InvalidSqlSnafu {
            msg: "SET ANNOTATIONS cannot be used with ADD/MODIFY/DROP ANNOTATIONS",
        }
        .fail(),
        Some(AnnotationOperations::PartialChanges(label_changes)) => {
            label_changes.push(annotation_change);
            Ok(())
        }
        None => {
            *annotation_ops = Some(AnnotationOperations::PartialChanges(vec![
                annotation_change,
            ]));
            Ok(())
        }
    }
}

fn apply_notify_change(
    ops: &mut Option<NotifyChannelOperations>,
    change: NotifyChannelChange,
) -> Result<()> {
    match ops {
        Some(NotifyChannelOperations::ReplaceAll(_)) => InvalidSqlSnafu {
            msg: "SET NOTIFY cannot be used with ADD/DROP NOTIFY",
        }
        .fail(),
        Some(NotifyChannelOperations::PartialChanges(changes)) => {
            changes.push(change);
            Ok(())
        }
        None => {
            *ops = Some(NotifyChannelOperations::PartialChanges(vec![change]));
            Ok(())
        }
    }
}

#[cfg(test)]
mod tests {
    use std::time::Duration;

    use crate::dialect::GreptimeDbDialect;
    use crate::parser::ParserContext;
    use crate::parsers::alter_parser::trigger::{apply_label_change, apply_label_replacement};
    use crate::statements::OptionMap;
    use crate::statements::alter::trigger::{LabelChange, LabelOperations};
    use crate::statements::create::trigger::{DurationExpr, TriggerOn};
    use crate::statements::statement::Statement;

    #[test]
    fn test_parse_alter_without_alter_options() {
        // Failed case: No alter options.
        // Note: "ALTER TRIGGER" is matched.
        let sql = r#"public.old_trigger"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let result = ctx.parse_alter_trigger();
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_set_query() {
        // Passed case: SET QUERY.
        // Note: "ALTER TRIGGER" is matched.
        let sql = r#"public.old_trigger ON (SELECT * FROM test_table) EVERY '5 minute'::INTERVAL"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let stmt = ctx.parse_alter_trigger().unwrap();
        let Statement::AlterTrigger(alter) = stmt else {
            panic!("Expected AlterTrigger statement");
        };
        let TriggerOn {
            query,
            query_interval,
        } = alter.operation.trigger_on.unwrap();
        let DurationExpr { duration, raw_expr } = query_interval;
        assert_eq!(query.to_string(), "SELECT * FROM test_table");
        assert_eq!(raw_expr, "'5 minute'::INTERVAL");
        assert_eq!(duration, Duration::from_secs(300));
        assert!(alter.operation.rename.is_none());
        assert!(alter.operation.label_operations.is_none());
        assert!(alter.operation.annotation_operations.is_none());
        assert!(alter.operation.notify_channel_operations.is_none());

        // Failed case: multi SET QUERY.
        let sql = r#"public.old_trigger ON (SELECT * FROM test_table) EVERY '5 minute'::INTERVAL
            ON (SELECT * FROM another_table) EVERY '10 minute'::INTERVAL"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let result = ctx.parse_alter_trigger();
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_alter_trigger_rename() {
        // Note: "ALTER TRIGGER" is matched.
        let sql = r#"public.old_trigger RENAME TO `newTrigger`"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let stmt = ctx.parse_alter_trigger().unwrap();
        let Statement::AlterTrigger(alter) = stmt else {
            panic!("Expected AlterTrigger statement");
        };
        let trigger_name = alter.trigger_name.0;
        assert_eq!(trigger_name.len(), 2);
        assert_eq!(
            trigger_name
                .iter()
                .map(|x| x.to_string())
                .collect::<Vec<_>>()
                .join(" "),
            "public old_trigger"
        );
        assert_eq!(alter.operation.rename, Some("newTrigger".to_string()));
    }

    #[test]
    fn test_parse_alter_trigger_labels() {
        // Passed case: SET LABELS.
        // Note: "ALTER TRIGGER" is matched.
        let sql = r#"test_trigger SET LABELS (Key1='value1', 'KEY2'='VALUE2')"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let stmt = ctx.parse_alter_trigger().unwrap();
        let Statement::AlterTrigger(alter) = stmt else {
            panic!("Expected AlterTrigger statement");
        };
        let Some(LabelOperations::ReplaceAll(labels)) = alter.operation.label_operations else {
            panic!("Expected ReplaceAll label operations");
        };

        assert_eq!(labels.len(), 2);
        assert_eq!(labels.get("key1"), Some("value1"));
        assert_eq!(labels.get("key2"), Some("VALUE2"));

        // Passed case: multiple ADD/DROP/MODIFY LABELS.
        let sql = r#"test_trigger ADD LABELS (key1='value1') MODIFY LABELS (key2='value2') DROP LABELS ('key3')"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let stmt = ctx.parse_alter_trigger().unwrap();
        let Statement::AlterTrigger(alter) = stmt else {
            panic!("Expected AlterTrigger statement");
        };
        let Some(LabelOperations::PartialChanges(changes)) = alter.operation.label_operations
        else {
            panic!("Expected PartialChanges label operations");
        };
        assert_eq!(changes.len(), 3);
        let change0 = changes.first().unwrap();
        let LabelChange::Add(labels) = change0 else {
            panic!("Expected Add label change");
        };
        assert_eq!(labels.len(), 1);
        assert_eq!(labels.get("key1"), Some("value1"));

        let change1 = changes.get(1).unwrap();
        let LabelChange::Modify(labels) = change1 else {
            panic!("Expected Modify label change");
        };
        assert_eq!(labels.len(), 1);
        assert_eq!(labels.get("key2"), Some("value2"));

        let change2 = changes.get(2).unwrap();
        let LabelChange::Drop(names) = change2 else {
            panic!("Expected Drop label change");
        };
        assert_eq!(names.len(), 1);
        assert_eq!(names.first().unwrap(), "key3");

        // Failed case: Duplicate SET LABELS.
        let sql =
            r#"test_trigger SET LABELS (key1='value1', key2='value2') SET LABELS (key3='value3')"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let result = ctx.parse_alter_trigger();
        assert!(result.is_err());

        // Failed case: SET LABELS with ADD/MODIFY/DROP LABELS.
        let sql =
            r#"test_trigger SET LABELS (key1='value1', key2='value2') ADD LABELS (key3='value3')"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let result = ctx.parse_alter_trigger();
        assert!(result.is_err());
        let sql = r#"test_trigger SET LABELS (key1='value1', key2='value2') DROP LABELS ('key3')"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let result = ctx.parse_alter_trigger();
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_rename_to() {
        let sql = r#"RENAME TO new_trigger_name"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let new_trigger_name = ctx.parse_rename_to(false).unwrap();
        assert_eq!(new_trigger_name.value, "new_trigger_name");
        assert_eq!(new_trigger_name.quote_style, None);

        let sql = r#"RENAME TO "New_Trigger_Name""#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let new_trigger_name = ctx.parse_rename_to(false).unwrap();
        assert_eq!(new_trigger_name.value, "New_Trigger_Name");
        assert_eq!(new_trigger_name.quote_style, Some('"'));

        // Failed case: Missing new_trigger_name.
        let sql = r#"RENAME TO"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let result = ctx.parse_rename_to(false);
        assert!(result.is_err());

        // Failed case: Missing `TO` keyword.
        let sql = r#"RENAME"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let result = ctx.parse_rename_to(false);
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_trigger_label_names() {
        let sql = r#"LABELS (key1, KEY2, key3)"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let labels = ctx.parse_trigger_label_names(false).unwrap();
        let expected_labels = vec!["key1".to_string(), "key2".to_string(), "key3".to_string()];
        assert_eq!(labels, expected_labels,);

        let sql = r#"LABELS ('key1', `key2`, "key3",)"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let labels = ctx.parse_trigger_label_names(false).unwrap();
        let expected_labels = vec!["key1".to_string(), "key2".to_string(), "key3".to_string()];
        assert_eq!(labels, expected_labels,);

        let sql = r#"LABELS ()"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let labels = ctx.parse_trigger_label_names(false).unwrap();
        assert!(labels.is_empty());
    }

    #[test]
    fn test_parse_trigger_annotation_names() {
        let sql = r#"ANNOTATIONS (key1, KEY2, key3)"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let annotations = ctx.parse_trigger_annotation_names(false).unwrap();
        let expected_annotations = vec!["key1".to_string(), "key2".to_string(), "key3".to_string()];
        assert_eq!(annotations, expected_annotations);

        let sql = r#"ANNOTATIONS (key1, `Key2`, "key3")"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let annotations = ctx.parse_trigger_annotation_names(false).unwrap();
        let expected_annotations = vec!["key1".to_string(), "key2".to_string(), "key3".to_string()];
        assert_eq!(annotations, expected_annotations);

        let sql = r#"ANNOTATIONS ()"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let annotations = ctx.parse_trigger_annotation_names(false).unwrap();
        assert!(annotations.is_empty());
    }

    #[test]
    fn test_parse_trigger_notify_names() {
        let sql = r#"NOTIFY (key1, KEY2, key3)"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let notify_names = ctx.parse_trigger_notify_names(false).unwrap();
        let expected_notify_names =
            vec!["key1".to_string(), "key2".to_string(), "key3".to_string()];
        assert_eq!(notify_names, expected_notify_names);

        let sql = r#"NOTIFY (key1, key2,)"#;
        let mut ctx = ParserContext::new(&GreptimeDbDialect {}, sql).unwrap();
        let notify_names = ctx.parse_trigger_notify_names(false).unwrap();
        let expected_notify_names = vec!["key1".to_string(), "key2".to_string()];
        assert_eq!(notify_names, expected_notify_names);
    }

    #[test]
    fn test_apply_label_changes() {
        let mut label_ops = None;

        let mut labels = OptionMap::default();
        labels.insert("key1".to_string(), "value1".to_string());
        labels.insert("key2".to_string(), "value2".to_string());

        apply_label_replacement(&mut label_ops, labels.clone()).unwrap();
        assert!(label_ops.is_some());

        // Set operations are mutually exclusive.
        let result = apply_label_replacement(&mut label_ops, labels.clone());
        assert!(result.is_err());

        // Set operations and Change operations are mutually exclusive.
        let result =
            apply_label_change(&mut label_ops, LabelChange::Drop(vec!["key1".to_string()]));
        assert!(result.is_err());

        let mut label_ops = None;

        let result = apply_label_change(&mut label_ops, LabelChange::Add(labels.clone()));
        assert!(result.is_ok());

        // Partial changes are not mutually exclusive.
        let result = apply_label_change(&mut label_ops, LabelChange::Modify(labels));
        assert!(result.is_ok());
        let result =
            apply_label_change(&mut label_ops, LabelChange::Drop(vec!["key1".to_string()]));
        assert!(result.is_ok());

        let ops = label_ops.unwrap();
        if let LabelOperations::PartialChanges(changes) = ops {
            assert_eq!(changes.len(), 3);
            assert!(matches!(changes[0], LabelChange::Add(_)));
            assert!(matches!(changes[1], LabelChange::Modify(_)));
            assert!(matches!(changes[2], LabelChange::Drop(_)));
        } else {
            panic!("Expected PartialChanges, got {:?}", ops);
        }
    }
}
