/*
 * Copyright (c) 2025 Raphael Amorim
 *
 * This file is part of flash, which is licensed
 * under GNU General Public License v3.0.
 */

use serde::{Deserialize, Serialize};

use crate::lexer::Lexer;
use crate::lexer::Position;
use crate::lexer::Token;
use crate::lexer::TokenKind;

/// AST node types
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Node {
    Command {
        name: String,
        args: Vec<String>,
        redirects: Vec<Redirect>,
    },
    Pipeline {
        commands: Vec<Node>,
    },
    List {
        statements: Vec<Node>,
        operators: Vec<String>, // ";" or "&" or "&&" or "||"
    },
    Assignment {
        name: String,
        value: Box<Node>,
    },
    CommandSubstitution {
        command: Box<Node>,
    },
    ArithmeticExpansion {
        expression: String,
    },
    ArithmeticCommand {
        expression: String,
    },
    Subshell {
        list: Box<Node>,
    },
    Comment(String),
    StringLiteral(String),
    SingleQuotedString(String), // Single-quoted strings that should not have variable expansion
    ExtGlobPattern {
        operator: char,        // ?, *, +, @, !
        patterns: Vec<String>, // The pattern list inside the parentheses
        suffix: String,        // Any text that follows the closing parenthesis
    },
    IfStatement {
        condition: Box<Node>,
        consequence: Box<Node>,
        alternative: Option<Box<Node>>,
    },
    ElifBranch {
        condition: Box<Node>,
        consequence: Box<Node>,
    },
    ElseBranch {
        consequence: Box<Node>,
    },
    CaseStatement {
        expression: Box<Node>,
        patterns: Vec<CasePattern>,
    },
    Array {
        elements: Vec<String>,
    },
    Function {
        name: String,
        body: Box<Node>,
    },
    FunctionCall {
        name: String,
        args: Vec<String>,
        redirects: Vec<Redirect>,
    },
    Export {
        name: String,
        value: Option<Box<Node>>, // None for export without assignment (export VAR)
    },
    Return {
        value: Option<Box<Node>>,
    },
    // Bash-specific features
    ExtendedTest {
        condition: Box<Node>,
    },
    HistoryExpansion {
        pattern: String,
    },
    Complete {
        options: Vec<String>,
        command: String,
    },
    ForLoop {
        variable: String,
        iterable: Box<Node>,
        body: Box<Node>,
    },
    WhileLoop {
        condition: Box<Node>,
        body: Box<Node>,
    },
    UntilLoop {
        condition: Box<Node>,
        body: Box<Node>,
    },
    Negation {
        command: Box<Node>,
    },
    SelectStatement {
        variable: String,
        items: Box<Node>,
        body: Box<Node>,
    },
    Group {
        list: Box<Node>,
    },
    ParameterExpansion {
        parameter: String,
        expansion_type: ParameterExpansionType,
    },
    ProcessSubstitution {
        command: Box<Node>,
        direction: ProcessSubstDirection,
    },
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ProcessSubstDirection {
    Input,  // <(cmd)
    Output, // >(cmd)
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ParameterExpansionType {
    Simple,                              // ${var}
    Default(String),                     // ${var:-default}
    Assign(String),                      // ${var:=default}
    Error(String),                       // ${var:?error}
    Alternative(String),                 // ${var:+alternative}
    Length,                              // ${#var}
    RemoveSmallestPrefix(String),        // ${var#pattern}
    RemoveLargestPrefix(String),         // ${var##pattern}
    RemoveSmallestSuffix(String),        // ${var%pattern}
    RemoveLargestSuffix(String),         // ${var%%pattern}
    Substring(Option<i32>, Option<i32>), // ${var:offset:length}
    Indirect,                            // ${!var}
    ArrayAll,                            // ${array[@]}
    ArrayStar,                           // ${array[*]}
    ArrayLength,                         // ${#array[@]}
    ArrayIndex(String),                  // ${array[index]}
}

/// Case pattern for case statements
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CasePattern {
    pub patterns: Vec<String>, // Multiple patterns separated by |
    pub body: Box<Node>,
}

/// Redirection types
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Redirect {
    #[serde(default)]
    pub fd: Option<i32>,
    pub kind: RedirectKind,
    pub file: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum RedirectKind {
    Input,       // <
    Output,      // >
    Append,      // >>
    HereDoc,     // <<
    HereDocDash, // <<-
    HereString,  // <<<
    InputDup,    // <&
    OutputDup,   // >&
}

/// Parser converts tokens into an AST
pub struct Parser {
    pub lexer: Lexer,
    pub current_token: Token,
    pub peek_token: Token,
}

impl Parser {
    pub fn new(lexer: Lexer) -> Self {
        let mut parser = Self {
            lexer,
            current_token: Token {
                kind: TokenKind::EOF,
                value: String::new(),
                position: Position::new(0, 0),
            },
            peek_token: Token {
                kind: TokenKind::EOF,
                value: String::new(),
                position: Position::new(0, 0),
            },
        };

        parser.next_token();
        parser.next_token();
        parser
    }

    pub fn next_token(&mut self) {
        self.current_token = self.peek_token.clone();
        self.peek_token = self.lexer.next_token();
    }

    // Function definition: name() { ... }
    fn parse_function_definition(&mut self) -> Node {
        // Get function name
        let name = match &self.current_token.kind {
            TokenKind::Word(word) => word.clone(),
            _ => String::new(),
        };

        self.next_token(); // Skip function name
        self.next_token(); // Skip '('
        self.next_token(); // Skip ')'

        // We expect a '{' to start the function body
        if self.current_token.kind != TokenKind::LBrace {
            // Handle error - expected '{'
            return Node::Command {
                name: String::new(),
                args: Vec::new(),
                redirects: Vec::new(),
            };
        }

        self.next_token(); // Skip '{'

        // Parse the function body until we hit '}'
        let body = self.parse_until_token_kind(TokenKind::RBrace);

        self.next_token(); // Skip '}'

        Node::Function {
            name,
            body: Box::new(body),
        }
    }

    // Function definition with keyword: function name { ... }
    fn parse_function_with_keyword(&mut self) -> Node {
        self.next_token(); // Skip 'function' keyword

        // Get function name
        let name = match &self.current_token.kind {
            TokenKind::Word(word) => word.clone(),
            _ => String::new(),
        };

        self.next_token(); // Skip function name

        // Check if there's the optional () syntax
        if self.current_token.kind == TokenKind::LParen {
            self.next_token(); // Skip '('
            if self.current_token.kind == TokenKind::RParen {
                self.next_token(); // Skip ')'
            }
        }

        // We expect a '{' to start the function body
        if self.current_token.kind != TokenKind::LBrace {
            // Handle error - expected '{'
            return Node::Command {
                name: String::new(),
                args: Vec::new(),
                redirects: Vec::new(),
            };
        }

        self.next_token(); // Skip '{'

        // Parse the function body until we hit '}'
        let body = self.parse_until_token_kind(TokenKind::RBrace);

        self.next_token(); // Skip '}'

        Node::Function {
            name,
            body: Box::new(body),
        }
    }

    pub fn parse_statement(&mut self) -> Option<Node> {
        match self.current_token.kind {
            TokenKind::Function => {
                // Handle function keyword: function func_name { ... }
                if matches!(self.peek_token.kind, TokenKind::Word(_)) {
                    Some(self.parse_function_with_keyword())
                } else {
                    // If not followed by a word, treat as a regular command
                    Some(self.parse_command())
                }
            }
            TokenKind::Word(ref word) => {
                // Check for function definition: func_name() { ... }
                if self.peek_token.kind == TokenKind::LParen {
                    // Use peek_next_token to look two tokens ahead for the ')'
                    let next_token = self.lexer.peek_next_token();
                    if next_token.kind == TokenKind::RParen {
                        return Some(self.parse_function_definition());
                    }
                }

                // Check for variable assignment (VAR=value)
                if self.peek_token.kind == TokenKind::Assignment {
                    return Some(self.parse_assignment());
                }

                // Check for export statement
                if word == "export" {
                    return Some(self.parse_export());
                }

                // Check for logical negation
                if word == "!" {
                    return Some(self.parse_negation());
                }

                let command_node = self.parse_command();
                Some(command_node)
            }
            TokenKind::If => Some(self.parse_if_statement()),
            TokenKind::Case => Some(self.parse_case_statement()),
            TokenKind::For => Some(self.parse_for_loop()),
            TokenKind::While => Some(self.parse_while_loop()),
            TokenKind::Until => Some(self.parse_until_loop()),
            TokenKind::Select => Some(self.parse_select_statement()),
            TokenKind::Elif => Some(self.parse_elif_branch()),
            TokenKind::Else => Some(self.parse_else_branch()),
            TokenKind::LParen => Some(self.parse_subshell()),
            TokenKind::ArithCommand => Some(self.parse_arithmetic_command()),
            TokenKind::Comment => {
                let comment = self.current_token.value.clone();
                self.next_token();
                Some(Node::Comment(comment))
            }
            TokenKind::ExtGlob(_) => Some(self.parse_extglob()),
            TokenKind::Export => Some(self.parse_export()),
            TokenKind::Return => Some(self.parse_return()),
            TokenKind::DoubleLBracket => Some(self.parse_extended_test()),
            TokenKind::History => Some(self.parse_history_expansion()),
            TokenKind::ParamExpansion => Some(self.parse_parameter_expansion()),
            TokenKind::ProcessSubstIn => {
                Some(self.parse_process_substitution(ProcessSubstDirection::Input))
            }
            TokenKind::ProcessSubstOut => {
                Some(self.parse_process_substitution(ProcessSubstDirection::Output))
            }
            TokenKind::Complete => Some(self.parse_complete()),
            _ => None,
        }
    }

    // Parse export statement: export VAR=value or export VAR
    fn parse_export(&mut self) -> Node {
        self.next_token(); // Skip 'export' keyword

        // Get variable name
        let name = match &self.current_token.kind {
            TokenKind::Word(word) => word.clone(),
            _ => {
                // Handle error case - return empty export
                return Node::Export {
                    name: String::new(),
                    value: None,
                };
            }
        };

        self.next_token(); // Skip variable name

        // Check if there's an assignment
        if self.current_token.kind == TokenKind::Assignment {
            self.next_token(); // Skip '='

            // Check for array assignment like export arch=('x86_64')
            if self.current_token.kind == TokenKind::LParen {
                let array_value = self.parse_array_value();
                return Node::Export {
                    name,
                    value: Some(Box::new(array_value)),
                };
            }

            // Parse the value (similar to regular assignment)
            let value = self.parse_assignment_value();
            Node::Export {
                name,
                value: Some(Box::new(value)),
            }
        } else {
            // Export without assignment (export VAR)
            Node::Export { name, value: None }
        }
    }

    // Parse return statement: return [value]
    fn parse_return(&mut self) -> Node {
        self.next_token(); // Skip 'return' keyword

        // Check if there's a return value
        let value = match self.current_token.kind {
            TokenKind::Semicolon | TokenKind::Newline | TokenKind::EOF | TokenKind::RBrace => {
                // No return value
                None
            }
            _ => {
                // Parse the return value
                Some(Box::new(self.parse_assignment_value()))
            }
        };

        Node::Return { value }
    }

    // Helper method to parse assignment values (extracted from parse_assignment)
    fn parse_assignment_value(&mut self) -> Node {
        // First, check if this is a simple single-token case
        match self.current_token.kind {
            TokenKind::Quote => return self.parse_quoted_string(TokenKind::Quote),
            TokenKind::SingleQuote => return self.parse_quoted_string(TokenKind::SingleQuote),
            TokenKind::CmdSubst => return self.parse_command_substitution(),
            TokenKind::ArithSubst => return self.parse_arithmetic_expansion(),
            _ => {}
        }

        // For complex cases with multiple tokens, build a concatenated string
        let mut result = String::new();
        let mut has_tokens = false;

        // Continue reading tokens until we hit a statement terminator
        while !matches!(
            self.current_token.kind,
            TokenKind::Semicolon
                | TokenKind::Newline
                | TokenKind::EOF
                | TokenKind::Pipe
                | TokenKind::And
                | TokenKind::Or
        ) {
            has_tokens = true;
            match self.current_token.kind {
                TokenKind::Quote => {
                    if let Node::StringLiteral(s) = self.parse_quoted_string(TokenKind::Quote) {
                        result.push_str(&s);
                    }
                }
                TokenKind::SingleQuote => {
                    if let Node::SingleQuotedString(s) =
                        self.parse_quoted_string(TokenKind::SingleQuote)
                    {
                        result.push_str(&s);
                    }
                }
                TokenKind::CmdSubst => {
                    // For command substitution in concatenated context, preserve the syntax
                    let cmd_node = self.parse_command_substitution();
                    if let Node::CommandSubstitution { .. } = cmd_node {
                        // We'll need to handle this during evaluation
                        result.push_str("$(...)"); // Placeholder for now
                    }
                }
                TokenKind::ArithSubst => {
                    // For arithmetic expansion in concatenated context, preserve the syntax
                    let arith_node = self.parse_arithmetic_expansion();
                    if let Node::ArithmeticExpansion { expression } = arith_node {
                        result.push_str(&format!("$(({expression}))"));
                    }
                }
                TokenKind::Dollar => {
                    // Handle variable expansion
                    result.push('$');
                    self.next_token(); // Skip $
                    if let TokenKind::Word(var_name) = &self.current_token.kind {
                        result.push_str(var_name);
                        self.next_token();
                    }
                }
                TokenKind::Word(ref word) => {
                    result.push_str(word);
                    self.next_token();
                }
                // Handle keywords as assignment values
                TokenKind::Continue => {
                    result.push_str("continue");
                    self.next_token();
                }
                TokenKind::Break => {
                    result.push_str("break");
                    self.next_token();
                }
                TokenKind::If => {
                    result.push_str("if");
                    self.next_token();
                }
                TokenKind::Then => {
                    result.push_str("then");
                    self.next_token();
                }
                TokenKind::Else => {
                    result.push_str("else");
                    self.next_token();
                }
                TokenKind::Elif => {
                    result.push_str("elif");
                    self.next_token();
                }
                TokenKind::Fi => {
                    result.push_str("fi");
                    self.next_token();
                }
                TokenKind::For => {
                    result.push_str("for");
                    self.next_token();
                }
                TokenKind::While => {
                    result.push_str("while");
                    self.next_token();
                }
                TokenKind::Do => {
                    result.push_str("do");
                    self.next_token();
                }
                TokenKind::Done => {
                    result.push_str("done");
                    self.next_token();
                }
                TokenKind::Until => {
                    result.push_str("until");
                    self.next_token();
                }
                TokenKind::In => {
                    result.push_str("in");
                    self.next_token();
                }
                TokenKind::Function => {
                    result.push_str("function");
                    self.next_token();
                }
                TokenKind::Return => {
                    result.push_str("return");
                    self.next_token();
                }
                TokenKind::Export => {
                    result.push_str("export");
                    self.next_token();
                }
                _ => {
                    // Stop on any other token
                    break;
                }
            }
        }

        if has_tokens {
            Node::StringLiteral(result)
        } else {
            // No tokens found, return empty string
            Node::StringLiteral(String::new())
        }
    }

    // Helper method to parse array values
    fn parse_array_value(&mut self) -> Node {
        self.next_token(); // Skip '('

        let mut array_elements = Vec::new();

        while self.current_token.kind != TokenKind::RParen
            && self.current_token.kind != TokenKind::EOF
        {
            match &self.current_token.kind {
                TokenKind::Word(word) => {
                    array_elements.push(word.clone());
                    self.next_token();
                }
                TokenKind::SingleQuote | TokenKind::Quote => {
                    let quote_type = self.current_token.kind.clone();
                    let quoted_value = self.parse_quoted_string_value(quote_type);
                    array_elements.push(quoted_value);
                }
                _ => {
                    self.next_token();
                }
            }
        }

        if self.current_token.kind == TokenKind::RParen {
            self.next_token();
        }

        Node::Array {
            elements: array_elements,
        }
    }

    // Helper method to parse quoted strings
    fn parse_quoted_string(&mut self, quote_type: TokenKind) -> Node {
        let quoted_value = self.parse_quoted_string_value(quote_type.clone());
        match quote_type {
            TokenKind::SingleQuote => Node::SingleQuotedString(quoted_value),
            _ => Node::StringLiteral(quoted_value),
        }
    }

    // Helper method to get the string value from quoted content
    fn parse_quoted_string_value(&mut self, quote_type: TokenKind) -> String {
        self.next_token(); // Skip opening quote

        let mut quoted_value = String::new();
        while self.current_token.kind != quote_type && self.current_token.kind != TokenKind::EOF {
            if let TokenKind::Word(word) = &self.current_token.kind {
                quoted_value.push_str(word);
            }
            self.next_token();
        }

        if self.current_token.kind == quote_type {
            self.next_token(); // Skip closing quote
        }

        quoted_value
    }

    // Parse if statement
    fn parse_if_statement(&mut self) -> Node {
        self.next_token(); // Skip "if"

        // Parse condition as a single command until we hit "then"
        let condition = self.parse_condition_until_token_kind(TokenKind::Then);

        self.next_token(); // Skip "then"

        // Parse consequence (body of the if block)
        let consequence =
            self.parse_until_token_kinds(&[TokenKind::Elif, TokenKind::Else, TokenKind::Fi]);

        // Handle elif/else chaining
        let alternative = self.parse_elif_else_chain();

        Node::IfStatement {
            condition: Box::new(condition),
            consequence: Box::new(consequence),
            alternative,
        }
    }

    // Parse a chain of elif/else statements
    fn parse_elif_else_chain(&mut self) -> Option<Box<Node>> {
        match self.current_token.kind {
            TokenKind::Elif => {
                self.next_token(); // Skip "elif"

                // Parse elif condition
                let elif_condition = self.parse_condition_until_token_kind(TokenKind::Then);
                self.next_token(); // Skip "then"

                // Parse elif consequence
                let elif_consequence = self.parse_until_token_kinds(&[
                    TokenKind::Elif,
                    TokenKind::Else,
                    TokenKind::Fi,
                ]);

                // Check what follows this elif and handle chaining properly
                match self.current_token.kind {
                    TokenKind::Elif => {
                        // More elif statements - create nested IfStatement
                        let next_alternative = self.parse_elif_else_chain();
                        Some(Box::new(Node::IfStatement {
                            condition: Box::new(elif_condition),
                            consequence: Box::new(elif_consequence),
                            alternative: next_alternative,
                        }))
                    }
                    TokenKind::Else => {
                        // Else follows - create IfStatement with else alternative
                        let else_branch = self.parse_else_branch();
                        Some(Box::new(Node::IfStatement {
                            condition: Box::new(elif_condition),
                            consequence: Box::new(elif_consequence),
                            alternative: Some(Box::new(else_branch)),
                        }))
                    }
                    TokenKind::Fi => {
                        // End of if statement - just return ElifBranch for simple cases
                        self.next_token(); // Skip "fi"
                        Some(Box::new(Node::ElifBranch {
                            condition: Box::new(elif_condition),
                            consequence: Box::new(elif_consequence),
                        }))
                    }
                    _ => Some(Box::new(Node::ElifBranch {
                        condition: Box::new(elif_condition),
                        consequence: Box::new(elif_consequence),
                    })),
                }
            }
            TokenKind::Else => Some(Box::new(self.parse_else_branch())),
            TokenKind::Fi => {
                self.next_token(); // Skip "fi"
                None
            }
            _ => None,
        }
    }

    // Parse elif branch
    fn parse_elif_branch(&mut self) -> Node {
        self.next_token(); // Skip "elif"

        // Parse condition as a single command until we hit "then"
        let condition = self.parse_condition_until_token_kind(TokenKind::Then);

        self.next_token(); // Skip "then"

        // Parse consequence (body of the elif block)
        let consequence =
            self.parse_until_token_kinds(&[TokenKind::Elif, TokenKind::Else, TokenKind::Fi]);

        // Just return the ElifBranch - let the caller handle chaining
        Node::ElifBranch {
            condition: Box::new(condition),
            consequence: Box::new(consequence),
        }
    }

    // Parse else branch
    fn parse_else_branch(&mut self) -> Node {
        self.next_token(); // Skip "else"

        // Parse consequence (body of the else block)
        let consequence = self.parse_until_token_kind(TokenKind::Fi);

        self.next_token(); // Skip "fi"

        Node::ElseBranch {
            consequence: Box::new(consequence),
        }
    }

    // Parse case statement: case word in pattern) commands ;; ... esac
    fn parse_case_statement(&mut self) -> Node {
        self.next_token(); // Skip "case"

        // Parse the expression to match against - this should be a simple word or quoted string
        let expression = match &self.current_token.kind {
            TokenKind::Word(word) => {
                let expr = Node::StringLiteral(word.clone());
                self.next_token();
                expr
            }
            TokenKind::Quote => {
                // Handle quoted strings
                self.parse_quoted_string(TokenKind::Quote)
            }
            TokenKind::CmdSubst => {
                // Handle command substitution
                self.parse_command_substitution()
            }
            _ => {
                // Fallback to parsing as a condition
                self.parse_condition_until_token_kind(TokenKind::In)
            }
        };

        // Expect "in" keyword
        if self.current_token.kind == TokenKind::In {
            self.next_token(); // Skip "in"
        }

        let mut patterns = Vec::new();

        // Parse case patterns until we hit "esac"
        while self.current_token.kind != TokenKind::Esac
            && self.current_token.kind != TokenKind::EOF
        {
            // Skip any newlines or whitespace
            while self.current_token.kind == TokenKind::Newline {
                self.next_token();
            }

            if self.current_token.kind == TokenKind::Esac {
                break;
            }

            // Parse pattern(s) - can be multiple patterns separated by |
            let mut pattern_list = Vec::new();

            // Parse the first pattern
            if let TokenKind::Word(pattern) = &self.current_token.kind {
                pattern_list.push(pattern.clone());
                self.next_token();

                // Check for additional patterns separated by |
                while self.current_token.kind == TokenKind::Pipe {
                    self.next_token(); // Skip |
                    if let TokenKind::Word(pattern) = &self.current_token.kind {
                        pattern_list.push(pattern.clone());
                        self.next_token();
                    }
                }
            }

            // Expect )
            if self.current_token.kind == TokenKind::RParen {
                self.next_token(); // Skip )
            }

            // Skip any newlines
            while self.current_token.kind == TokenKind::Newline {
                self.next_token();
            }

            // Parse the body until we hit ;; or esac
            // Use a simpler approach - parse until we hit ;; or esac
            let mut body_statements = Vec::new();
            let mut body_operators = Vec::new();

            while self.current_token.kind != TokenKind::DoubleSemicolon
                && self.current_token.kind != TokenKind::Esac
                && self.current_token.kind != TokenKind::EOF
            {
                if let Some(statement) = self.parse_statement() {
                    body_statements.push(statement);

                    // Handle operators between statements
                    if self.current_token.kind == TokenKind::Semicolon {
                        body_operators.push(";".to_string());
                        self.next_token();
                    } else if self.current_token.kind == TokenKind::Newline {
                        body_operators.push("\n".to_string());
                        self.next_token();
                    }
                }
            }

            let body = if body_statements.len() == 1 && body_operators.is_empty() {
                body_statements.into_iter().next().unwrap()
            } else {
                Node::List {
                    statements: body_statements,
                    operators: body_operators,
                }
            };

            // Skip ;; if present
            if self.current_token.kind == TokenKind::DoubleSemicolon {
                self.next_token();
            }

            // Skip any newlines after ;;
            while self.current_token.kind == TokenKind::Newline {
                self.next_token();
            }

            if !pattern_list.is_empty() {
                patterns.push(CasePattern {
                    patterns: pattern_list,
                    body: Box::new(body),
                });
            }
        }

        // Skip "esac"
        if self.current_token.kind == TokenKind::Esac {
            self.next_token();
        }

        Node::CaseStatement {
            expression: Box::new(expression),
            patterns,
        }
    }

    // Parse for loop: for var in list; do ... done
    fn parse_for_loop(&mut self) -> Node {
        self.next_token(); // Skip "for"

        // Parse variable name
        let variable = if let TokenKind::Word(var_name) = &self.current_token.kind {
            var_name.clone()
        } else {
            return Node::Command {
                name: "echo".to_string(),
                args: vec!["syntax error: expected variable name after 'for'".to_string()],
                redirects: Vec::new(),
            };
        };
        self.next_token();

        // Expect "in"
        if self.current_token.kind != TokenKind::In {
            return Node::Command {
                name: "echo".to_string(),
                args: vec!["syntax error: expected 'in' after variable name".to_string()],
                redirects: Vec::new(),
            };
        }
        self.next_token(); // Skip "in"

        // Parse iterable (could be words, brace expansion, etc.)
        let iterable = self.parse_for_iterable();

        // Skip optional semicolon or newline
        while self.current_token.kind == TokenKind::Semicolon
            || self.current_token.kind == TokenKind::Newline
        {
            self.next_token();
        }

        // Expect "do"
        if self.current_token.kind != TokenKind::Do {
            return Node::Command {
                name: "echo".to_string(),
                args: vec!["syntax error: expected 'do' after iterable".to_string()],
                redirects: Vec::new(),
            };
        }
        self.next_token(); // Skip "do"

        // Parse body until "done"
        let body = self.parse_until_token_kind(TokenKind::Done);

        self.next_token(); // Skip "done"

        Node::ForLoop {
            variable,
            iterable: Box::new(iterable),
            body: Box::new(body),
        }
    }

    // Parse the iterable part of a for loop (handles brace expansion)
    fn parse_for_iterable(&mut self) -> Node {
        let mut elements = Vec::new();

        while self.current_token.kind != TokenKind::Semicolon
            && self.current_token.kind != TokenKind::Newline
            && self.current_token.kind != TokenKind::Do
            && self.current_token.kind != TokenKind::EOF
        {
            if let TokenKind::Word(word) = &self.current_token.kind {
                // Check for brace expansion like {1..10} or {a,b,c}
                if word.starts_with('{')
                    && word.ends_with('}')
                    && (word.contains("..") || word.contains(','))
                {
                    if let Some(expanded) = self.expand_brace_pattern(word) {
                        elements.extend(expanded);
                    } else {
                        elements.push(word.clone());
                    }
                } else {
                    elements.push(word.clone());
                }
            }
            self.next_token();
        }

        Node::Array { elements }
    }

    // Expand brace patterns like {1..10}, {a..z}, or {a,b,c}
    fn expand_brace_pattern(&self, word: &str) -> Option<Vec<String>> {
        if !word.starts_with('{') || !word.ends_with('}') {
            return None;
        }

        let inner = &word[1..word.len() - 1]; // Remove { and }

        // Check for range expansion first
        if inner.contains("..") {
            return self.expand_brace_range(word);
        }

        // Check for comma-separated expansion
        if inner.contains(',') {
            let items: Vec<&str> = inner.split(',').collect();
            let mut result = Vec::new();
            for item in items {
                result.push(item.trim().to_string());
            }
            return Some(result);
        }

        None
    }

    // Expand brace ranges like {1..10} or {a..z}
    fn expand_brace_range(&self, word: &str) -> Option<Vec<String>> {
        if !word.starts_with('{') || !word.ends_with('}') || !word.contains("..") {
            return None;
        }

        let inner = &word[1..word.len() - 1]; // Remove { and }
        let parts: Vec<&str> = inner.split("..").collect();
        if parts.len() != 2 {
            return None;
        }

        let start = parts[0];
        let end = parts[1];

        // Try numeric expansion
        if let (Ok(start_num), Ok(end_num)) = (start.parse::<i32>(), end.parse::<i32>()) {
            let mut result = Vec::new();
            if start_num <= end_num {
                for i in start_num..=end_num {
                    result.push(i.to_string());
                }
            } else {
                for i in (end_num..=start_num).rev() {
                    result.push(i.to_string());
                }
            }
            return Some(result);
        }

        // Try character expansion (single characters only)
        if start.len() == 1 && end.len() == 1 {
            let start_char = start.chars().next().unwrap();
            let end_char = end.chars().next().unwrap();
            let mut result = Vec::new();

            if start_char <= end_char {
                for c in start_char..=end_char {
                    result.push(c.to_string());
                }
            } else {
                for c in (end_char..=start_char).rev() {
                    result.push(c.to_string());
                }
            }
            return Some(result);
        }

        None
    }

    // Parse while loop: while condition; do body; done
    fn parse_while_loop(&mut self) -> Node {
        self.next_token(); // Skip "while"

        // Parse condition until "do"
        let condition = self.parse_condition_until_token_kind(TokenKind::Do);

        // Expect "do"
        if self.current_token.kind != TokenKind::Do {
            return Node::Command {
                name: "echo".to_string(),
                args: vec!["syntax error: expected 'do' after while condition".to_string()],
                redirects: Vec::new(),
            };
        }
        self.next_token(); // Skip "do"

        // Parse body until "done"
        let body = self.parse_until_token_kind(TokenKind::Done);

        self.next_token(); // Skip "done"

        Node::WhileLoop {
            condition: Box::new(condition),
            body: Box::new(body),
        }
    }

    // Parse until loop: until condition; do body; done
    fn parse_until_loop(&mut self) -> Node {
        self.next_token(); // Skip "until"

        // Parse condition until "do"
        let condition = self.parse_condition_until_token_kind(TokenKind::Do);

        // Expect "do"
        if self.current_token.kind != TokenKind::Do {
            return Node::Command {
                name: "echo".to_string(),
                args: vec!["syntax error: expected 'do' after until condition".to_string()],
                redirects: Vec::new(),
            };
        }
        self.next_token(); // Skip "do"

        // Parse body until "done"
        let body = self.parse_until_token_kind(TokenKind::Done);

        self.next_token(); // Skip "done"

        Node::UntilLoop {
            condition: Box::new(condition),
            body: Box::new(body),
        }
    }

    // Parse select statement: select var in items; do body; done
    fn parse_select_statement(&mut self) -> Node {
        self.next_token(); // Skip "select"

        // Parse variable name
        let variable = if let TokenKind::Word(var_name) = &self.current_token.kind {
            let var = var_name.clone();
            self.next_token();
            var
        } else {
            return Node::Command {
                name: "echo".to_string(),
                args: vec!["syntax error: expected variable name after 'select'".to_string()],
                redirects: Vec::new(),
            };
        };

        // Expect "in"
        if self.current_token.kind != TokenKind::In {
            return Node::Command {
                name: "echo".to_string(),
                args: vec!["syntax error: expected 'in' after select variable".to_string()],
                redirects: Vec::new(),
            };
        }
        self.next_token(); // Skip "in"

        // Parse items until "do" or semicolon/newline
        let items = self.parse_select_items();

        // Skip semicolons and newlines
        while self.current_token.kind == TokenKind::Semicolon
            || self.current_token.kind == TokenKind::Newline
        {
            self.next_token();
        }

        // Expect "do"
        if self.current_token.kind != TokenKind::Do {
            return Node::Command {
                name: "echo".to_string(),
                args: vec!["syntax error: expected 'do' after select items".to_string()],
                redirects: Vec::new(),
            };
        }
        self.next_token(); // Skip "do"

        // Parse body until "done"
        let body = self.parse_until_token_kind(TokenKind::Done);

        self.next_token(); // Skip "done"

        Node::SelectStatement {
            variable,
            items: Box::new(items),
            body: Box::new(body),
        }
    }

    // Parse items for select statement
    fn parse_select_items(&mut self) -> Node {
        let mut items = Vec::new();

        while self.current_token.kind != TokenKind::Do
            && self.current_token.kind != TokenKind::Semicolon
            && self.current_token.kind != TokenKind::Newline
            && self.current_token.kind != TokenKind::EOF
        {
            if let TokenKind::Word(item) = &self.current_token.kind {
                items.push(item.clone());
                self.next_token();
            } else {
                break;
            }
        }

        if items.is_empty() {
            // If no items specified, default to positional parameters
            Node::StringLiteral("$@".to_string())
        } else {
            Node::Array { elements: items }
        }
    }

    // method to parse a single command condition until a specific token kind is encountered
    fn parse_condition_until_token_kind(&mut self, stop_at: TokenKind) -> Node {
        // Parse a single command as the condition
        if let Some(statement) = self.parse_statement() {
            // Skip any semicolons or newlines before the stop token
            while (self.current_token.kind == TokenKind::Semicolon
                || self.current_token.kind == TokenKind::Newline)
                && self.current_token.kind != stop_at
                && self.current_token.kind != TokenKind::EOF
            {
                self.next_token();
            }
            statement
        } else {
            // Return empty command if no valid statement found
            Node::Command {
                name: String::new(),
                args: Vec::new(),
                redirects: Vec::new(),
            }
        }
    }

    // method to parse statements until a specific token kind is encountered
    fn parse_until_token_kind(&mut self, stop_at: TokenKind) -> Node {
        let mut statements = Vec::new();
        let mut operators = Vec::new();

        while self.current_token.kind != stop_at && self.current_token.kind != TokenKind::EOF {
            if let Some(statement) = self.parse_statement() {
                statements.push(statement);

                // Check for operators between statements
                match self.current_token.kind {
                    TokenKind::Semicolon => {
                        operators.push(";".to_string());
                        self.next_token();
                    }
                    TokenKind::Newline => {
                        operators.push("\n".to_string());
                        self.next_token();
                    }
                    TokenKind::And => {
                        operators.push("&&".to_string());
                        self.next_token();
                    }
                    TokenKind::Background => {
                        operators.push("&".to_string());
                        self.next_token();
                    }
                    TokenKind::Or => {
                        operators.push("||".to_string());
                        self.next_token();
                    }
                    _ => {
                        if statements.len() > 1 && operators.len() < statements.len() - 1 {
                            operators.push("".to_string());
                        }
                    }
                }
            } else {
                // Skip tokens that don't form valid statements
                self.next_token();
            }
        }

        // Ensure we have the right number of operators
        while operators.len() < statements.len() - 1 {
            operators.push("".to_string());
        }

        // If we have statements, return a List node; otherwise, return an empty Command node
        if !statements.is_empty() {
            Node::List {
                statements,
                operators,
            }
        } else {
            Node::Command {
                name: String::new(),
                args: Vec::new(),
                redirects: Vec::new(),
            }
        }
    }

    // Helper method to parse statements until one of several token kinds is encountered
    fn parse_until_token_kinds(&mut self, stop_at: &[TokenKind]) -> Node {
        let mut statements = Vec::new();
        let mut operators = Vec::new();

        while !stop_at.contains(&self.current_token.kind)
            && self.current_token.kind != TokenKind::EOF
        {
            if let Some(statement) = self.parse_statement() {
                statements.push(statement);

                // Check for operators between statements
                match self.current_token.kind {
                    TokenKind::Semicolon => {
                        operators.push(";".to_string());
                        self.next_token();
                    }
                    TokenKind::Newline => {
                        operators.push("\n".to_string());
                        self.next_token();
                    }
                    TokenKind::And => {
                        operators.push("&&".to_string());
                        self.next_token();
                    }
                    TokenKind::Background => {
                        operators.push("&".to_string());
                        self.next_token();
                    }
                    TokenKind::Or => {
                        operators.push("||".to_string());
                        self.next_token();
                    }
                    _ => {
                        if statements.len() > 1 && operators.len() < statements.len() - 1 {
                            operators.push("".to_string());
                        }
                    }
                }
            } else {
                // Skip tokens that don't form valid statements
                self.next_token();
            }
        }

        // If we have statements, return a List node; otherwise, return an empty Command node
        if !statements.is_empty() {
            // Ensure we have the right number of operators
            while operators.len() < statements.len() - 1 {
                operators.push("".to_string());
            }

            Node::List {
                statements,
                operators,
            }
        } else {
            Node::Command {
                name: String::new(),
                args: Vec::new(),
                redirects: Vec::new(),
            }
        }
    }

    fn parse_extglob(&mut self) -> Node {
        let operator = match &self.current_token.kind {
            TokenKind::ExtGlob(op) => *op,
            _ => panic!("Expected an extended glob operator"),
        };

        self.next_token(); // Skip the operator token

        // Parse patterns inside parentheses
        let mut patterns = Vec::new();
        let mut current_pattern = String::new();

        // We expect to be at the beginning of the pattern list
        // Keep reading until we reach the closing parenthesis
        while self.current_token.kind != TokenKind::RParen
            && self.current_token.kind != TokenKind::EOF
        {
            match &self.current_token.kind {
                TokenKind::Word(word) => {
                    current_pattern.push_str(word);
                }
                TokenKind::Pipe => {
                    patterns.push(current_pattern);
                    current_pattern = String::new();
                }
                _ => {
                    // Other tokens will be part of the pattern or handled elsewhere
                    if !current_pattern.is_empty() {
                        patterns.push(current_pattern);
                        current_pattern = String::new();
                    }
                }
            }
            self.next_token();
        }

        // Add the final pattern if not empty
        if !current_pattern.is_empty() {
            patterns.push(current_pattern);
        }

        // Skip the closing parenthesis
        if self.current_token.kind == TokenKind::RParen {
            self.next_token();
        }

        // Capture any suffix that follows the closing parenthesis
        let mut suffix = String::new();
        while let TokenKind::Word(word) = &self.current_token.kind {
            suffix.push_str(word);
            self.next_token();
        }

        Node::ExtGlobPattern {
            operator,
            patterns,
            suffix,
        }
    }

    pub fn parse_assignment(&mut self) -> Node {
        let name = match &self.current_token.kind {
            TokenKind::Word(word) => word.clone(),
            _ => String::new(),
        };

        self.next_token(); // Skip variable name
        self.next_token(); // Skip '='

        // Check for array assignment like arch=('x86_64')
        if self.current_token.kind == TokenKind::LParen {
            return self.parse_array_assignment(name);
        }

        // Check for quotes, command substitution, or plain word
        let value = match self.current_token.kind {
            TokenKind::Quote => {
                // Handle double quoted string
                self.next_token(); // Skip opening quote

                let mut quoted_value = String::new();
                while self.current_token.kind != TokenKind::Quote
                    && self.current_token.kind != TokenKind::EOF
                {
                    if let TokenKind::Word(word) = &self.current_token.kind {
                        quoted_value.push_str(word);
                    }
                    self.next_token();
                }

                if self.current_token.kind == TokenKind::Quote {
                    self.next_token(); // Skip closing quote
                }

                Box::new(Node::StringLiteral(quoted_value))
            }
            TokenKind::SingleQuote => {
                // Handle single quoted string
                self.next_token(); // Skip opening quote

                let mut quoted_value = String::new();
                while self.current_token.kind != TokenKind::SingleQuote
                    && self.current_token.kind != TokenKind::EOF
                {
                    if let TokenKind::Word(word) = &self.current_token.kind {
                        quoted_value.push_str(word);
                    }
                    self.next_token();
                }

                if self.current_token.kind == TokenKind::SingleQuote {
                    self.next_token(); // Skip closing quote
                }

                Box::new(Node::StringLiteral(quoted_value))
            }
            TokenKind::CmdSubst => {
                // Handle command substitution like $(...)
                let cmd_subst = self.parse_command_substitution();
                Box::new(cmd_subst)
            }
            TokenKind::ArithSubst => {
                // Handle arithmetic expansion like $((...))
                let arith_subst = self.parse_arithmetic_expansion();
                Box::new(arith_subst)
            }
            TokenKind::Word(ref word) => {
                let value = word.clone();
                self.next_token(); // Skip value
                Box::new(Node::StringLiteral(value))
            }
            // Handle keywords as assignment values
            TokenKind::Continue => {
                self.next_token();
                Box::new(Node::StringLiteral("continue".to_string()))
            }
            TokenKind::Break => {
                self.next_token();
                Box::new(Node::StringLiteral("break".to_string()))
            }
            TokenKind::If => {
                self.next_token();
                Box::new(Node::StringLiteral("if".to_string()))
            }
            TokenKind::Then => {
                self.next_token();
                Box::new(Node::StringLiteral("then".to_string()))
            }
            TokenKind::Else => {
                self.next_token();
                Box::new(Node::StringLiteral("else".to_string()))
            }
            TokenKind::Elif => {
                self.next_token();
                Box::new(Node::StringLiteral("elif".to_string()))
            }
            TokenKind::Fi => {
                self.next_token();
                Box::new(Node::StringLiteral("fi".to_string()))
            }
            TokenKind::For => {
                self.next_token();
                Box::new(Node::StringLiteral("for".to_string()))
            }
            TokenKind::While => {
                self.next_token();
                Box::new(Node::StringLiteral("while".to_string()))
            }
            TokenKind::Do => {
                self.next_token();
                Box::new(Node::StringLiteral("do".to_string()))
            }
            TokenKind::Done => {
                self.next_token();
                Box::new(Node::StringLiteral("done".to_string()))
            }
            TokenKind::In => {
                self.next_token();
                Box::new(Node::StringLiteral("in".to_string()))
            }
            TokenKind::Function => {
                self.next_token();
                Box::new(Node::StringLiteral("function".to_string()))
            }
            TokenKind::Export => {
                self.next_token();
                Box::new(Node::StringLiteral("export".to_string()))
            }
            _ => {
                // Handle unexpected token or empty value
                Box::new(Node::StringLiteral(String::new()))
            }
        };

        Node::Assignment { name, value }
    }

    fn parse_array_assignment(&mut self, name: String) -> Node {
        self.next_token(); // Skip '('

        let mut array_elements = Vec::new();

        // Parse array elements until closing parenthesis
        while self.current_token.kind != TokenKind::RParen
            && self.current_token.kind != TokenKind::EOF
        {
            match &self.current_token.kind {
                TokenKind::Word(word) => {
                    array_elements.push(word.clone());
                    self.next_token();
                }
                TokenKind::SingleQuote => {
                    self.next_token(); // Skip opening quote

                    let mut quoted_value = String::new();
                    while self.current_token.kind != TokenKind::SingleQuote
                        && self.current_token.kind != TokenKind::EOF
                    {
                        if let TokenKind::Word(word) = &self.current_token.kind {
                            quoted_value.push_str(word);
                        }
                        self.next_token();
                    }

                    if self.current_token.kind == TokenKind::SingleQuote {
                        self.next_token(); // Skip closing quote
                    }

                    array_elements.push(quoted_value);
                }
                TokenKind::Quote => {
                    self.next_token(); // Skip opening quote

                    let mut quoted_value = String::new();
                    while self.current_token.kind != TokenKind::Quote
                        && self.current_token.kind != TokenKind::EOF
                    {
                        if let TokenKind::Word(word) = &self.current_token.kind {
                            quoted_value.push_str(word);
                        }
                        self.next_token();
                    }

                    if self.current_token.kind == TokenKind::Quote {
                        self.next_token(); // Skip closing quote
                    }

                    array_elements.push(quoted_value);
                }
                _ => {
                    // Skip other tokens like newlines or spaces in array
                    self.next_token();
                }
            }
        }

        if self.current_token.kind == TokenKind::RParen {
            self.next_token(); // Skip the closing parenthesis
        }

        Node::Assignment {
            name,
            value: Box::new(Node::Array {
                elements: array_elements,
            }),
        }
    }

    pub fn parse_command(&mut self) -> Node {
        let name = match &self.current_token.kind {
            TokenKind::Word(word) => word.clone(),
            _ => String::new(),
        };

        self.next_token();

        let mut args = Vec::new();
        let mut redirects = Vec::new();

        // Loop to collect arguments and handle quotes
        loop {
            match &self.current_token.kind {
                TokenKind::Word(word) => {
                    // Support fd-prefixed redirects like: 2>/dev/null, 1>>out.log, 2>&1
                    if word.chars().all(|c| c.is_ascii_digit())
                        && matches!(
                            self.peek_token.kind,
                            TokenKind::Less
                                | TokenKind::Great
                                | TokenKind::DGreat
                                | TokenKind::HereDoc
                                | TokenKind::HereDocDash
                                | TokenKind::HereString
                        )
                    {
                        let fd = word.parse::<i32>().ok();
                        self.next_token(); // Move to redirect operator
                        let redirect = self.parse_redirect_with_fd(fd);
                        redirects.push(redirect);
                        continue;
                    }

                    // Special case: if command name is "[" and we encounter "]", include it and stop
                    if name == "[" && word == "]" {
                        args.push(word.clone());
                        self.next_token(); // Skip the "]"
                        break;
                    }
                    // Check if this word is a variable reference (starts with $)
                    // and keep it as a single token
                    args.push(word.clone());
                    self.next_token();
                }
                TokenKind::ArithSubst => {
                    // Handle arithmetic expansion like $((expr))
                    let arith_expansion = self.parse_arithmetic_expansion();
                    if let Node::ArithmeticExpansion { expression } = arith_expansion {
                        args.push(format!("$(({expression}))"));
                    }
                }
                TokenKind::CmdSubst => {
                    // Handle command substitution like $(...)
                    let cmd_subst = self.parse_command_substitution();
                    if let Node::CommandSubstitution { command } = &cmd_subst {
                        if let Node::Command {
                            name,
                            args: cmd_args,
                            redirects,
                        } = command.as_ref()
                        {
                            if redirects.is_empty() && cmd_args.is_empty() {
                                args.push(format!("$({name})"));
                            } else if redirects.is_empty() {
                                let mut cmd_str = name.clone();
                                for arg in cmd_args {
                                    cmd_str.push(' ');
                                    cmd_str.push_str(arg);
                                }
                                args.push(format!("$({cmd_str})"));
                            } else {
                                args.push("$(...)".to_string());
                            }
                        } else {
                            args.push("$(...)".to_string());
                        }
                    }
                }
                TokenKind::Quote => {
                    // Handle double quoted strings
                    let quoted = self.parse_quoted_string(TokenKind::Quote);
                    if let Node::StringLiteral(s) = quoted {
                        args.push(s);
                    }
                }
                TokenKind::SingleQuote => {
                    // Handle single quoted strings
                    let quoted = self.parse_quoted_string(TokenKind::SingleQuote);
                    if let Node::SingleQuotedString(s) = quoted {
                        args.push(s);
                    }
                }
                // Handle keywords as regular arguments when they appear in command arguments
                TokenKind::Continue => {
                    args.push("continue".to_string());
                    self.next_token();
                }
                TokenKind::Break => {
                    args.push("break".to_string());
                    self.next_token();
                }
                TokenKind::If => {
                    args.push("if".to_string());
                    self.next_token();
                }
                TokenKind::Then => {
                    args.push("then".to_string());
                    self.next_token();
                }
                TokenKind::Else => {
                    args.push("else".to_string());
                    self.next_token();
                }
                TokenKind::Elif => {
                    args.push("elif".to_string());
                    self.next_token();
                }
                TokenKind::Fi => {
                    args.push("fi".to_string());
                    self.next_token();
                }
                TokenKind::For => {
                    args.push("for".to_string());
                    self.next_token();
                }
                TokenKind::While => {
                    args.push("while".to_string());
                    self.next_token();
                }
                TokenKind::Do => {
                    args.push("do".to_string());
                    self.next_token();
                }
                TokenKind::Done => {
                    args.push("done".to_string());
                    self.next_token();
                }
                TokenKind::In => {
                    args.push("in".to_string());
                    self.next_token();
                }
                TokenKind::Function => {
                    args.push("function".to_string());
                    self.next_token();
                }
                TokenKind::Export => {
                    args.push("export".to_string());
                    self.next_token();
                }
                TokenKind::ExtGlob(_) => {
                    // Handle extended glob pattern in command arguments
                    let extglob = self.parse_extglob();

                    // Convert the ExtGlobPattern to a string representation
                    let pattern_str = match &extglob {
                        Node::ExtGlobPattern {
                            operator,
                            patterns,
                            suffix,
                        } => {
                            let patterns_joined = patterns.join("|");
                            format!("{operator}({patterns_joined}){suffix}")
                        }
                        _ => String::new(),
                    };

                    args.push(pattern_str);
                }
                TokenKind::Less
                | TokenKind::Great
                | TokenKind::DGreat
                | TokenKind::HereDoc
                | TokenKind::HereDocDash
                | TokenKind::HereString => {
                    let redirect = self.parse_redirect_with_fd(None);
                    redirects.push(redirect);
                }
                TokenKind::Dollar => {
                    // Handle variable references explicitly (like $VAR or ${VAR})
                    let mut var_ref = "$".to_string();
                    self.next_token(); // Skip $

                    if let TokenKind::LBrace = &self.current_token.kind {
                        // Handle ${VAR} syntax
                        var_ref.push('{');
                        self.next_token(); // Skip {

                        if let TokenKind::Word(word) = &self.current_token.kind {
                            var_ref.push_str(word);
                            self.next_token(); // Skip variable name/expression
                        }

                        if let TokenKind::RBrace = &self.current_token.kind {
                            var_ref.push('}');
                            self.next_token(); // Skip }
                        }
                    } else if let TokenKind::Word(word) = &self.current_token.kind {
                        // Handle $VAR syntax
                        var_ref.push_str(word);
                        self.next_token(); // Skip variable name
                    }

                    // Check if the next token is also a Dollar or Word that should be concatenated
                    // This handles cases like $i$j where consecutive variables should be one argument
                    while let TokenKind::Dollar = &self.current_token.kind {
                        match &self.current_token.kind {
                            TokenKind::Dollar => {
                                // Another variable reference - concatenate it
                                var_ref.push('$');
                                self.next_token(); // Skip $

                                if let TokenKind::LBrace = &self.current_token.kind {
                                    // Handle ${VAR} syntax
                                    var_ref.push('{');
                                    self.next_token(); // Skip {

                                    if let TokenKind::Word(word) = &self.current_token.kind {
                                        var_ref.push_str(word);
                                        self.next_token(); // Skip variable name/expression
                                    }

                                    if let TokenKind::RBrace = &self.current_token.kind {
                                        var_ref.push('}');
                                        self.next_token(); // Skip }
                                    }
                                } else if let TokenKind::Word(word) = &self.current_token.kind {
                                    // Handle $VAR syntax
                                    var_ref.push_str(word);
                                    self.next_token(); // Skip variable name
                                }
                            }
                            _ => {
                                // Stop concatenating when we hit something else
                                break;
                            }
                        }
                    }

                    args.push(var_ref);
                }
                TokenKind::Assignment => {
                    // In command context, treat = as a regular argument
                    args.push("=".to_string());
                    self.next_token();
                }
                TokenKind::LBrace => {
                    // Handle brace expansion like {1..5} or {a,b,c}
                    let mut brace_content = String::new();
                    brace_content.push('{');
                    self.next_token(); // Skip the '{'

                    // Collect tokens until we find the matching '}'
                    while self.current_token.kind != TokenKind::RBrace
                        && self.current_token.kind != TokenKind::EOF
                    {
                        match &self.current_token.kind {
                            TokenKind::Word(word) => {
                                brace_content.push_str(word);
                            }
                            _ => {
                                // For other tokens, use their string representation
                                brace_content.push_str(&self.current_token.value);
                            }
                        }
                        self.next_token();
                    }

                    if self.current_token.kind == TokenKind::RBrace {
                        brace_content.push('}');
                        self.next_token(); // Skip the '}'
                    }

                    args.push(brace_content);
                }
                _ => break, // Exit when we're not on a word, quote, or redirect token
            }
        }

        // Check for pipeline
        if self.current_token.kind == TokenKind::Pipe {
            self.next_token(); // Skip the '|'

            // Parse the next command in the pipeline
            let next_command = self.parse_command();

            let mut commands = vec![Node::Command {
                name,
                args,
                redirects,
            }];

            // Add the next command to the pipeline
            match next_command {
                Node::Pipeline {
                    commands: more_commands,
                } => {
                    commands.extend(more_commands);
                }
                _ => {
                    commands.push(next_command);
                }
            }

            Node::Pipeline { commands }
        } else {
            Node::Command {
                name,
                args,
                redirects,
            }
        }
    }

    pub fn parse_command_substitution(&mut self) -> Node {
        self.next_token(); // Skip '$('

        // Parse the command inside the substitution
        let mut statements = Vec::new();
        let mut operators = Vec::new();

        while self.current_token.kind != TokenKind::RParen
            && self.current_token.kind != TokenKind::EOF
        {
            if let Some(statement) = self.parse_statement() {
                statements.push(statement);

                match self.current_token.kind {
                    TokenKind::Semicolon => {
                        operators.push(";".to_string());
                        self.next_token();
                    }
                    TokenKind::Newline => {
                        operators.push("\n".to_string());
                        self.next_token();
                    }
                    TokenKind::And => {
                        operators.push("&&".to_string());
                        self.next_token();
                    }
                    TokenKind::Or => {
                        operators.push("||".to_string());
                        self.next_token();
                    }
                    _ => {
                        if statements.len() > 1 && operators.len() < statements.len() - 1 {
                            operators.push("".to_string());
                        }
                    }
                }
            } else {
                self.next_token();
            }
        }

        // Ensure we have the right number of operators
        while operators.len() < statements.len() - 1 {
            operators.push("".to_string());
        }

        // Create the appropriate node based on the content
        let command_node = if statements.len() == 1 && operators.is_empty() {
            statements.remove(0)
        } else {
            Node::List {
                statements,
                operators,
            }
        };

        self.next_token(); // Skip ')'

        Node::CommandSubstitution {
            command: Box::new(command_node),
        }
    }

    pub fn parse_arithmetic_expansion(&mut self) -> Node {
        self.next_token(); // Skip '$(('

        let mut expression = String::new();
        let mut paren_count = 2; // We start with 2 open parentheses

        // Read until we find the matching closing parentheses
        while paren_count > 0 && self.current_token.kind != TokenKind::EOF {
            match &self.current_token.kind {
                TokenKind::LParen => {
                    paren_count += 1;
                    expression.push('(');
                    self.next_token();
                }
                TokenKind::RParen => {
                    paren_count -= 1;
                    // Only add ')' to expression if it's not part of the closing '))'
                    if paren_count > 1 {
                        expression.push(')');
                    }
                    self.next_token();
                }
                TokenKind::Word(word) => {
                    if !expression.is_empty() && !expression.ends_with(' ') {
                        expression.push(' ');
                    }
                    expression.push_str(word);
                    self.next_token();
                }
                TokenKind::Dollar => {
                    expression.push('$');
                    self.next_token();
                }
                TokenKind::Assignment => {
                    expression.push('=');
                    self.next_token();
                }
                _ => {
                    // For unhandled tokens, add their value but be careful about parentheses
                    let token_value = &self.current_token.value;
                    if token_value != ")" {
                        // Don't add stray closing parentheses
                        if !expression.is_empty()
                            && !expression.ends_with(' ')
                            && !token_value.is_empty()
                        {
                            expression.push(' ');
                        }
                        expression.push_str(token_value);
                    }
                    self.next_token();
                }
            }
        }

        Node::ArithmeticExpansion {
            expression: expression.trim().to_string(),
        }
    }

    pub fn parse_arithmetic_command(&mut self) -> Node {
        self.next_token(); // Skip '(('

        let mut expression = String::new();
        let mut paren_count = 2; // We start with 2 open parentheses

        // Read until we find the matching closing parentheses
        while paren_count > 0 && self.current_token.kind != TokenKind::EOF {
            match &self.current_token.kind {
                TokenKind::LParen => {
                    paren_count += 1;
                    expression.push('(');
                    self.next_token();
                }
                TokenKind::RParen => {
                    paren_count -= 1;
                    // Only add ')' to expression if it's not part of the closing '))'
                    if paren_count > 1 {
                        expression.push(')');
                    }
                    self.next_token();
                }
                TokenKind::Word(word) => {
                    if !expression.is_empty()
                        && !expression.ends_with(' ')
                        && !expression.ends_with('(')
                    {
                        expression.push(' ');
                    }
                    expression.push_str(word);
                    self.next_token();
                }
                TokenKind::Dollar => {
                    if !expression.is_empty()
                        && !expression.ends_with(' ')
                        && !expression.ends_with('(')
                    {
                        expression.push(' ');
                    }
                    expression.push('$');
                    self.next_token();

                    // Handle the variable name that follows the $
                    match &self.current_token.kind {
                        TokenKind::Word(word) => {
                            expression.push_str(word);
                            self.next_token();
                        }
                        TokenKind::LBrace => {
                            // Handle ${var} syntax
                            expression.push('{');
                            self.next_token();
                            if let TokenKind::Word(word) = &self.current_token.kind {
                                expression.push_str(word);
                                self.next_token();
                            }
                            if self.current_token.kind == TokenKind::RBrace {
                                expression.push('}');
                                self.next_token();
                            }
                        }
                        _ => {
                            // Just $ by itself, which is valid
                        }
                    }
                }
                TokenKind::Assignment => {
                    if !expression.is_empty() && !expression.ends_with(' ') {
                        expression.push(' ');
                    }
                    expression.push('=');
                    self.next_token();

                    // Check if the next token is also Assignment to handle ==
                    if self.current_token.kind == TokenKind::Assignment {
                        expression.push('=');
                        self.next_token();
                    }
                }
                TokenKind::Less => {
                    if !expression.is_empty() && !expression.ends_with(' ') {
                        expression.push(' ');
                    }
                    expression.push('<');
                    self.next_token();

                    // Check if the next token is Assignment to handle <=
                    if self.current_token.kind == TokenKind::Assignment {
                        expression.push('=');
                        self.next_token();
                    }
                }
                TokenKind::Great => {
                    if !expression.is_empty() && !expression.ends_with(' ') {
                        expression.push(' ');
                    }
                    expression.push('>');
                    self.next_token();

                    // Check if the next token is Assignment to handle >=
                    if self.current_token.kind == TokenKind::Assignment {
                        expression.push('=');
                        self.next_token();
                    }
                }
                TokenKind::And => {
                    if !expression.is_empty() && !expression.ends_with(' ') {
                        expression.push(' ');
                    }
                    expression.push_str("&&");
                    self.next_token();
                }
                TokenKind::Or => {
                    if !expression.is_empty() && !expression.ends_with(' ') {
                        expression.push(' ');
                    }
                    expression.push_str("||");
                    self.next_token();
                }
                TokenKind::ArithSubst => {
                    // Handle nested arithmetic substitution $((
                    if !expression.is_empty()
                        && !expression.ends_with(' ')
                        && !expression.ends_with('(')
                    {
                        expression.push(' ');
                    }
                    expression.push_str("$((");
                    self.next_token();

                    // Parse the nested arithmetic content until we find the matching ))
                    let mut nested_paren_count = 2; // We start with 2 open parentheses from $((

                    while nested_paren_count > 0 && self.current_token.kind != TokenKind::EOF {
                        match &self.current_token.kind {
                            TokenKind::LParen => {
                                nested_paren_count += 1;
                                expression.push('(');
                                self.next_token();
                            }
                            TokenKind::RParen => {
                                nested_paren_count -= 1;
                                expression.push(')');
                                self.next_token();
                            }
                            TokenKind::ArithSubst => {
                                // Handle deeply nested arithmetic substitution
                                expression.push_str(" $((");
                                nested_paren_count += 2; // Add 2 for the new $((
                                self.next_token();
                            }
                            TokenKind::Word(word) => {
                                if !expression.ends_with('(') && !expression.ends_with(' ') {
                                    expression.push(' ');
                                }
                                expression.push_str(word);
                                self.next_token();
                            }
                            _ => {
                                // Add other tokens as-is
                                let token_value = &self.current_token.value;
                                if !token_value.is_empty() {
                                    if !expression.ends_with('(') && !expression.ends_with(' ') {
                                        expression.push(' ');
                                    }
                                    expression.push_str(token_value);
                                }
                                self.next_token();
                            }
                        }
                    }
                }
                _ => {
                    // For unhandled tokens, add their value but be careful about parentheses
                    let token_value = &self.current_token.value;
                    if token_value != ")" {
                        // Don't add stray closing parentheses
                        if !expression.is_empty()
                            && !expression.ends_with(' ')
                            && !token_value.is_empty()
                            && !expression.ends_with('(')
                        {
                            expression.push(' ');
                        }
                        expression.push_str(token_value);
                    }
                    self.next_token();
                }
            }
        }

        Node::ArithmeticCommand {
            expression: expression.trim().to_string(),
        }
    }

    // Enhanced version to handle multiple variable assignments
    pub fn parse_command_with_assignments(&mut self) -> Node {
        // Store the first variable and its value
        let var_name = match &self.current_token.kind {
            TokenKind::Word(word) => word.clone(),
            _ => String::new(),
        };

        self.next_token(); // Skip variable name
        self.next_token(); // Skip '='

        // Check if this is a command substitution
        let var_value = if self.current_token.kind == TokenKind::CmdSubst {
            let cmd_substitution = self.parse_command_substitution();
            Box::new(cmd_substitution)
        } else {
            // Regular string value
            let value = match &self.current_token.kind {
                TokenKind::Word(word) => word.clone(),
                _ => String::new(),
            };

            self.next_token(); // Skip value
            Box::new(Node::StringLiteral(value))
        };

        let first_assignment = Node::Assignment {
            name: var_name,
            value: var_value,
        };

        // Does have more assignments?
        let mut assignments = vec![first_assignment];

        while let TokenKind::Word(ref _word) = self.current_token.kind {
            if let TokenKind::Assignment = self.peek_token.kind {
                // Parse another assignment
                let next_assignment = self.parse_assignment();
                assignments.push(next_assignment);
            } else {
                // start of a command that follows the assignments
                let command = self.parse_command();
                assignments.push(command);
                break;
            }
        }

        // If we only have assignments with no following command
        if assignments.len() == 1 {
            return assignments[0].clone();
        }

        // create a list containing all assignments (and potentially a command)
        Node::List {
            statements: assignments.clone(),
            operators: vec!["".to_string(); assignments.len() - 1],
        }
    }

    pub fn parse_script(&mut self) -> Node {
        let mut statements = Vec::new();
        let mut operators = Vec::new();

        while self.current_token.kind != TokenKind::EOF {
            if let Some(statement) = self.parse_statement() {
                statements.push(statement);

                match self.current_token.kind {
                    TokenKind::Semicolon => {
                        operators.push(";".to_string());
                        self.next_token();
                    }
                    TokenKind::Newline => {
                        operators.push("\n".to_string());
                        self.next_token();
                    }
                    TokenKind::And => {
                        operators.push("&&".to_string());
                        self.next_token();
                    }
                    TokenKind::Background => {
                        operators.push("&".to_string());
                        self.next_token();
                    }
                    TokenKind::Or => {
                        operators.push("||".to_string());
                        self.next_token();
                    }
                    _ => {
                        // Don't add an empty operator if we've reached the end
                        if self.current_token.kind != TokenKind::EOF
                            && statements.len() > operators.len() + 1
                        {
                            operators.push("".to_string());
                        }
                    }
                }
            } else {
                // Skip tokens that don't form valid statements
                self.next_token();
            }
        }

        // make sure we have the right number of operators
        while operators.len() < statements.len() - 1 {
            operators.push("".to_string());
        }

        Node::List {
            statements,
            operators,
        }
    }

    fn parse_redirect_with_fd(&mut self, fd: Option<i32>) -> Redirect {
        let mut kind = match self.current_token.kind {
            TokenKind::Less => RedirectKind::Input,
            TokenKind::Great => RedirectKind::Output,
            TokenKind::DGreat => RedirectKind::Append,
            TokenKind::HereDoc => RedirectKind::HereDoc,
            TokenKind::HereDocDash => RedirectKind::HereDocDash,
            TokenKind::HereString => RedirectKind::HereString,
            _ => panic!("Expected a redirection token"),
        };

        if matches!(kind, RedirectKind::HereDoc | RedirectKind::HereDocDash) {
            // IMPORTANT: don't advance with self.next_token() here.
            // Parser keeps one-token lookahead, and advancing once would pre-read
            // the first here-doc body token as peek_token.
            let delimiter = match &self.peek_token.kind {
                TokenKind::Word(word) => word.clone(),
                _ => self.peek_token.value.clone(),
            };
            let content = self
                .lexer
                .read_here_document(&delimiter, matches!(kind, RedirectKind::HereDocDash));
            // We consumed operator+delimiter logically and advanced lexer manually;
            // resync parser tokens from lexer head.
            self.current_token = self.lexer.next_token();
            self.peek_token = self.lexer.next_token();
            return Redirect {
                fd,
                kind,
                file: content,
            };
        }

        self.next_token(); // Skip the redirection operator

        let file = match &self.current_token.kind {
            TokenKind::Background => {
                // Support forms like 2>&1 where '&' is tokenized separately.
                self.next_token(); // Skip '&'
                kind = match kind {
                    RedirectKind::Input => RedirectKind::InputDup,
                    _ => RedirectKind::OutputDup,
                };
                match &self.current_token.kind {
                    TokenKind::Word(word) => format!("&{word}"),
                    _ => "&".to_string(),
                }
            }
            TokenKind::Word(word) => {
                // Support forms like >&1 where '&1' may be tokenized as one word.
                if word.starts_with('&') {
                    kind = match kind {
                        RedirectKind::Input => RedirectKind::InputDup,
                        _ => RedirectKind::OutputDup,
                    };
                }
                word.clone()
            }
            _ => String::new(),
        };

        self.next_token(); // Skip the filename

        Redirect { fd, kind, file }
    }

    fn parse_subshell(&mut self) -> Node {
        self.next_token(); // Skip '('

        let mut statements = Vec::new();
        let mut operators = Vec::new();

        // Parse until we hit the closing parenthesis
        while self.current_token.kind != TokenKind::RParen
            && self.current_token.kind != TokenKind::EOF
        {
            // Try to parse a statement
            if let Some(statement) = self.parse_statement() {
                statements.push(statement);

                // Handle operators between statements
                match self.current_token.kind {
                    TokenKind::Semicolon => {
                        operators.push(";".to_string());
                        self.next_token();
                    }
                    TokenKind::Newline => {
                        operators.push("\n".to_string());
                        self.next_token();
                    }
                    TokenKind::And => {
                        operators.push("&&".to_string());
                        self.next_token();
                    }
                    TokenKind::Background => {
                        operators.push("&".to_string());
                        self.next_token();
                    }
                    TokenKind::Or => {
                        operators.push("||".to_string());
                        self.next_token();
                    }
                    TokenKind::RParen => {
                        // We're at the end parenthesis, don't add an operator
                        break;
                    }
                    _ => {
                        // If we have multiple statements but missing operators between them
                        // Only add blank operator if we're not at the end
                        if statements.len() > 1 && operators.len() < statements.len() - 1 {
                            operators.push("".to_string());
                        }
                    }
                }
            } else {
                // If we couldn't parse a statement, skip the token to avoid infinite loops
                if self.current_token.kind == TokenKind::RParen {
                    break;
                }
                self.next_token();
            }
        }

        // Ensure we have the correct number of operators (statements - 1)
        while operators.len() < statements.len().saturating_sub(1) {
            operators.push("".to_string());
        }

        // Skip closing parenthesis if present
        if self.current_token.kind == TokenKind::RParen {
            self.next_token();
        }

        // Create the subshell node
        let list_node = Node::List {
            statements,
            operators,
        };

        Node::Subshell {
            list: Box::new(list_node),
        }
    }

    // Parse extended test command: [[ condition ]]
    fn parse_extended_test(&mut self) -> Node {
        self.next_token(); // Skip '[['

        // Parse the condition inside [[ ]]
        let mut condition_parts = Vec::new();

        while self.current_token.kind != TokenKind::DoubleRBracket
            && self.current_token.kind != TokenKind::EOF
        {
            match &self.current_token.kind {
                TokenKind::Word(word) => {
                    condition_parts.push(word.clone());
                    self.next_token();
                }
                _ => {
                    condition_parts.push(self.current_token.value.clone());
                    self.next_token();
                }
            }
        }

        if self.current_token.kind == TokenKind::DoubleRBracket {
            self.next_token(); // Skip ']]'
        }

        // Create a command node that represents the extended test
        let condition = Node::Command {
            name: "[[".to_string(),
            args: condition_parts,
            redirects: Vec::new(),
        };

        Node::ExtendedTest {
            condition: Box::new(condition),
        }
    }

    // Parse history expansion: !pattern
    fn parse_history_expansion(&mut self) -> Node {
        let history_token = self.current_token.value.clone();
        self.next_token(); // Skip '!' or '!!'

        let pattern = if history_token == "!!" {
            // !! means repeat last command (empty pattern)
            String::new()
        } else {
            // ! followed by pattern
            match &self.current_token.kind {
                TokenKind::Word(word) => {
                    let pattern = word.clone();
                    self.next_token();
                    pattern
                }
                _ => String::new(),
            }
        };

        Node::HistoryExpansion { pattern }
    }

    // Parse parameter expansion: ${var}, ${var:-default}, etc.
    fn parse_parameter_expansion(&mut self) -> Node {
        self.next_token(); // Skip ${

        let mut parameter = String::new();
        let mut expansion_type = ParameterExpansionType::Simple;

        // Handle indirect expansion ${!var}
        if let TokenKind::Word(word) = &self.current_token.kind {
            if word == "!" {
                self.next_token(); // Skip !
                if let TokenKind::Word(var_name) = &self.current_token.kind {
                    parameter = var_name.clone();
                    expansion_type = ParameterExpansionType::Indirect;
                    self.next_token(); // Skip variable name
                }
            } else if word == "#" {
                // Length expansion ${#var}
                self.next_token(); // Skip #
                if let TokenKind::Word(var_name) = &self.current_token.kind {
                    parameter = var_name.clone();
                    expansion_type = ParameterExpansionType::Length;
                    self.next_token(); // Skip variable name
                }
            } else {
                // Regular variable name
                parameter = word.clone();
                self.next_token(); // Skip variable name

                // Check for expansion operators
                if let TokenKind::Word(op) = &self.current_token.kind {
                    match op.as_str() {
                        ":-" => {
                            // Default value ${var:-default}
                            self.next_token(); // Skip :-
                            let default_val = self.parse_parameter_expansion_value();
                            expansion_type = ParameterExpansionType::Default(default_val);
                        }
                        ":=" => {
                            // Assign default ${var:=default}
                            self.next_token(); // Skip :=
                            let default_val = self.parse_parameter_expansion_value();
                            expansion_type = ParameterExpansionType::Assign(default_val);
                        }
                        ":?" => {
                            // Error if unset ${var:?error}
                            self.next_token(); // Skip :?
                            let error_msg = self.parse_parameter_expansion_value();
                            expansion_type = ParameterExpansionType::Error(error_msg);
                        }
                        ":+" => {
                            // Alternative value ${var:+alt}
                            self.next_token(); // Skip :+
                            let alt_val = self.parse_parameter_expansion_value();
                            expansion_type = ParameterExpansionType::Alternative(alt_val);
                        }
                        "#" => {
                            // Remove smallest prefix ${var#pattern}
                            self.next_token(); // Skip #
                            let pattern = self.parse_parameter_expansion_value();
                            expansion_type = ParameterExpansionType::RemoveSmallestPrefix(pattern);
                        }
                        "##" => {
                            // Remove largest prefix ${var##pattern}
                            self.next_token(); // Skip ##
                            let pattern = self.parse_parameter_expansion_value();
                            expansion_type = ParameterExpansionType::RemoveLargestPrefix(pattern);
                        }
                        "%" => {
                            // Remove smallest suffix ${var%pattern}
                            self.next_token(); // Skip %
                            let pattern = self.parse_parameter_expansion_value();
                            expansion_type = ParameterExpansionType::RemoveSmallestSuffix(pattern);
                        }
                        "%%" => {
                            // Remove largest suffix ${var%%pattern}
                            self.next_token(); // Skip %%
                            let pattern = self.parse_parameter_expansion_value();
                            expansion_type = ParameterExpansionType::RemoveLargestSuffix(pattern);
                        }
                        _ if op.starts_with(':') => {
                            // Substring expansion ${var:offset:length}
                            let offset_str = &op[1..];
                            if let Ok(offset) = offset_str.parse::<i32>() {
                                self.next_token(); // Skip offset

                                // Check for length
                                let length =
                                    if let TokenKind::Word(len_str) = &self.current_token.kind {
                                        if let Ok(len) = len_str.parse::<i32>() {
                                            self.next_token(); // Skip length
                                            Some(len)
                                        } else {
                                            None
                                        }
                                    } else {
                                        None
                                    };

                                expansion_type =
                                    ParameterExpansionType::Substring(Some(offset), length);
                            }
                        }
                        _ => {
                            // Unknown operator, treat as simple expansion
                        }
                    }
                }
            }
        }

        // Skip closing brace
        if self.current_token.kind == TokenKind::RBrace {
            self.next_token();
        }

        Node::ParameterExpansion {
            parameter,
            expansion_type,
        }
    }

    // Parse the value part of parameter expansion (after operators like :-, :=, etc.)
    fn parse_parameter_expansion_value(&mut self) -> String {
        let mut value = String::new();

        // Collect tokens until we hit the closing brace
        while self.current_token.kind != TokenKind::RBrace
            && self.current_token.kind != TokenKind::EOF
        {
            match &self.current_token.kind {
                TokenKind::Word(word) => {
                    value.push_str(word);
                }
                TokenKind::Dollar => {
                    value.push('$');
                }
                _ => {
                    // For other tokens, add their string representation
                    value.push_str(&self.current_token.value);
                }
            }
            self.next_token();
        }

        value
    }

    // Parse process substitution: <(cmd) or >(cmd)
    fn parse_process_substitution(&mut self, direction: ProcessSubstDirection) -> Node {
        self.next_token(); // Skip <( or >(

        // Parse the command inside the process substitution
        let command = self.parse_until_token_kind(TokenKind::RParen);

        self.next_token(); // Skip )

        Node::ProcessSubstitution {
            command: Box::new(command),
            direction,
        }
    }

    // Parse complete command: complete [options] command
    fn parse_complete(&mut self) -> Node {
        self.next_token(); // Skip 'complete'

        let mut options = Vec::new();
        let mut command = String::new();

        // Parse options and command
        while self.current_token.kind != TokenKind::Newline
            && self.current_token.kind != TokenKind::Semicolon
            && self.current_token.kind != TokenKind::EOF
        {
            match &self.current_token.kind {
                TokenKind::Word(word) => {
                    if word.starts_with('-') {
                        options.push(word.clone());
                    } else {
                        // If we haven't found the command yet, this could be an option argument or the command
                        // For simplicity, add non-dash words as options until we find the last word
                        if command.is_empty() {
                            options.push(word.clone());
                        }
                    }
                    self.next_token();
                }
                _ => {
                    self.next_token();
                }
            }
        }

        // The last option should be the command
        if !options.is_empty() {
            command = options.pop().unwrap();
        }

        Node::Complete { options, command }
    }

    // Parse logical negation: ! command
    fn parse_negation(&mut self) -> Node {
        self.next_token(); // Skip '!'

        // Parse the command to negate
        let command = if let Some(cmd) = self.parse_statement() {
            Box::new(cmd)
        } else {
            // If no command follows, treat as empty command
            Box::new(Node::Command {
                name: "true".to_string(),
                args: vec![],
                redirects: vec![],
            })
        };

        Node::Negation { command }
    }
}

#[cfg(test)]
mod parser_tests {
    use super::*;
    use pretty_assertions::assert_eq;

    fn parse_test(input: &str) -> Node {
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);
        parser.parse_script()
    }

    fn create_parser(input: &str) -> Parser {
        let lexer = Lexer::new(input);
        Parser::new(lexer)
    }

    #[test]
    fn test_simple_command() {
        let input = "echo hello world";
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 1);
                assert_eq!(operators.len(), 0);

                match &statements[0] {
                    Node::Command {
                        name,
                        args,
                        redirects,
                    } => {
                        assert_eq!(name, "echo");
                        assert_eq!(args, &["hello", "world"]);
                        assert_eq!(redirects.len(), 0);
                    }
                    _ => panic!("Expected Command node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_simple_assignment() {
        let input = "value=123";
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 1);
                assert_eq!(operators.len(), 0);

                match &statements[0] {
                    Node::Assignment { name, value } => {
                        assert_eq!(name, "value");
                        match &**value {
                            Node::StringLiteral(val) => {
                                assert_eq!(val, "123");
                            }
                            _ => panic!("Expected StringLiteral node for value"),
                        }
                    }
                    _ => panic!("Expected Assignment node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_command_with_redirects() {
        let input = "cat file.txt > output.txt";
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators: _,
            } => {
                assert_eq!(statements.len(), 1);

                match &statements[0] {
                    Node::Command {
                        name,
                        args,
                        redirects,
                    } => {
                        assert_eq!(name, "cat");
                        assert_eq!(args, &["file.txt"]);
                        assert_eq!(redirects.len(), 1);
                        assert!(matches!(redirects[0].kind, RedirectKind::Output));
                        assert_eq!(redirects[0].file, "output.txt");
                    }
                    _ => panic!("Expected Command node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_multiple_redirects() {
        let input = "cat < input.txt > output.txt";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command {
                    name, redirects, ..
                } => {
                    assert_eq!(name, "cat");
                    assert_eq!(redirects.len(), 2);
                    assert!(matches!(redirects[0].kind, RedirectKind::Input));
                    assert_eq!(redirects[0].file, "input.txt");
                    assert!(matches!(redirects[1].kind, RedirectKind::Output));
                    assert_eq!(redirects[1].file, "output.txt");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_simple_pipeline() {
        let input = "ls -la | grep .rs | wc -l";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Pipeline { commands } => {
                    assert_eq!(commands.len(), 3);

                    match &commands[0] {
                        Node::Command { name, args, .. } => {
                            assert_eq!(name, "ls");
                            assert_eq!(args, &["-la"]);
                        }
                        _ => panic!("Expected Command node for first pipeline command"),
                    }

                    match &commands[1] {
                        Node::Command { name, args, .. } => {
                            assert_eq!(name, "grep");
                            assert_eq!(args, &[".rs"]);
                        }
                        _ => panic!("Expected Command node for second pipeline command"),
                    }

                    match &commands[2] {
                        Node::Command { name, args, .. } => {
                            assert_eq!(name, "wc");
                            assert_eq!(args, &["-l"]);
                        }
                        _ => panic!("Expected Command node for third pipeline command"),
                    }
                }
                _ => panic!("Expected Pipeline node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_pipeline_with_redirects() {
        let input = "cat file.txt | grep pattern > output.txt";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Pipeline { commands } => {
                    assert_eq!(commands.len(), 2);

                    match &commands[1] {
                        Node::Command { redirects, .. } => {
                            assert_eq!(redirects.len(), 1);
                            assert!(matches!(redirects[0].kind, RedirectKind::Output));
                            assert_eq!(redirects[0].file, "output.txt");
                        }
                        _ => panic!("Expected Command node with redirect"),
                    }
                }
                _ => panic!("Expected Pipeline node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_command_list_semicolon() {
        let input = "echo hello; echo world";
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 2);
                assert_eq!(operators.len(), 1);
                assert_eq!(operators[0], ";");

                match &statements[0] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "echo");
                        assert_eq!(args, &["hello"]);
                    }
                    _ => panic!("Expected Command node for first statement"),
                }

                match &statements[1] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "echo");
                        assert_eq!(args, &["world"]);
                    }
                    _ => panic!("Expected Command node for second statement"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_command_list_newline() {
        let input = "echo hello\necho world";
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 2);
                assert_eq!(operators.len(), 1);
                assert_eq!(operators[0], "\n");
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_basic_subshell() {
        let input = "(echo hello)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List { statements, .. } => {
                        assert_eq!(statements.len(), 1);
                        match &statements[0] {
                            Node::Command { name, args, .. } => {
                                assert_eq!(name, "echo");
                                assert_eq!(args, &["hello"]);
                            }
                            _ => panic!("Expected Command node inside subshell"),
                        }
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_semicolon() {
        let input = "(echo hello; echo world)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List {
                        statements,
                        operators,
                    } => {
                        assert_eq!(statements.len(), 2);
                        assert_eq!(operators.len(), 1);
                        assert_eq!(operators[0], ";");

                        match &statements[0] {
                            Node::Command { name, args, .. } => {
                                assert_eq!(name, "echo");
                                assert_eq!(args, &["hello"]);
                            }
                            _ => panic!("Expected first Command node"),
                        }

                        match &statements[1] {
                            Node::Command { name, args, .. } => {
                                assert_eq!(name, "echo");
                                assert_eq!(args, &["world"]);
                            }
                            _ => panic!("Expected second Command node"),
                        }
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_newline() {
        let input = "(echo hello\necho world)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List {
                        statements,
                        operators,
                    } => {
                        assert_eq!(statements.len(), 2);
                        assert_eq!(operators.len(), 1);
                        assert_eq!(operators[0], "\n");
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_and_operator() {
        let input = "(echo hello && echo world)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List {
                        statements,
                        operators,
                    } => {
                        assert_eq!(statements.len(), 2);
                        assert_eq!(operators.len(), 1);
                        assert_eq!(operators[0], "&&");
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_or_operator() {
        let input = "(echo hello || echo world)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List {
                        statements,
                        operators,
                    } => {
                        assert_eq!(statements.len(), 2);
                        assert_eq!(operators.len(), 1);
                        assert_eq!(operators[0], "||");
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_background() {
        let input = "(echo hello & echo world)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List {
                        statements,
                        operators,
                    } => {
                        assert_eq!(statements.len(), 2);
                        assert_eq!(operators.len(), 1);
                        assert_eq!(operators[0], "&");
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_empty_subshell() {
        let input = "()";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List { statements, .. } => {
                        assert_eq!(statements.len(), 0);
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_nested_subshells() {
        let input = "((echo inner); echo outer)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::ArithmeticCommand { expression } => {
                        assert_eq!(expression, "echo inner ; echo outer");
                    }
                    _ => panic!("Expected ArithmeticCommand node, got {:?}", statements[0]),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_multiple_subshells() {
        let input = "(echo one); (echo two)";
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 2);
                assert_eq!(operators.len(), 1);
                assert_eq!(operators[0], ";");

                // Check first subshell
                match &statements[0] {
                    Node::Subshell { list } => match &**list {
                        Node::List { statements, .. } => {
                            assert_eq!(statements.len(), 1);
                            match &statements[0] {
                                Node::Command { name, args, .. } => {
                                    assert_eq!(name, "echo");
                                    assert_eq!(args, &["one"]);
                                }
                                _ => panic!("Expected Command node in first subshell"),
                            }
                        }
                        _ => panic!("Expected List node inside first subshell"),
                    },
                    _ => panic!("Expected first Subshell node"),
                }

                // Check second subshell
                match &statements[1] {
                    Node::Subshell { list } => match &**list {
                        Node::List { statements, .. } => {
                            assert_eq!(statements.len(), 1);
                            match &statements[0] {
                                Node::Command { name, args, .. } => {
                                    assert_eq!(name, "echo");
                                    assert_eq!(args, &["two"]);
                                }
                                _ => panic!("Expected Command node in second subshell"),
                            }
                        }
                        _ => panic!("Expected List node inside second subshell"),
                    },
                    _ => panic!("Expected second Subshell node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_complex_commands() {
        let input = "(cd /tmp && ls -la | grep file > output.txt)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List {
                        statements,
                        operators,
                    } => {
                        assert_eq!(statements.len(), 2);
                        assert_eq!(operators.len(), 1);
                        assert_eq!(operators[0], "&&");

                        // Check first command (cd /tmp)
                        match &statements[0] {
                            Node::Command { name, args, .. } => {
                                assert_eq!(name, "cd");
                                assert_eq!(args, &["/tmp"]);
                            }
                            _ => panic!("Expected first Command node"),
                        }

                        // Check second command (ls -la | grep file > output.txt)
                        match &statements[1] {
                            Node::Pipeline { commands } => {
                                assert_eq!(commands.len(), 2);

                                // Check first command in pipeline (ls -la)
                                match &commands[0] {
                                    Node::Command { name, args, .. } => {
                                        assert_eq!(name, "ls");
                                        assert_eq!(args, &["-la"]);
                                    }
                                    _ => panic!("Expected first command in pipeline"),
                                }

                                // Check second command in pipeline (grep file > output.txt)
                                match &commands[1] {
                                    Node::Command {
                                        name,
                                        args,
                                        redirects,
                                    } => {
                                        assert_eq!(name, "grep");
                                        assert_eq!(args, &["file"]);
                                        assert_eq!(redirects.len(), 1);
                                        assert_eq!(redirects[0].file, "output.txt");
                                        assert!(matches!(redirects[0].kind, RedirectKind::Output));
                                    }
                                    _ => panic!("Expected second command in pipeline"),
                                }
                            }
                            _ => panic!("Expected Pipeline node"),
                        }
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_command_substitution() {
        let input = "echo $(echo hello)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "echo");
                    assert_eq!(args.len(), 1);

                    // This will depend on how your parser handles command substitution
                    // Could be stored as a command substitution node or as a string with "$(...)"
                    // The important thing is that it recognizes it's not a subshell
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_command_assignment() {
        let input = "result=$(cat file.txt)";
        let result = parse_test(input);

        // Test the assignment with command substitution
        match result {
            Node::List { statements, .. } => {
                assert!(matches!(statements[0], Node::Assignment { .. }));
            }
            _ => panic!("Expected List node"),
        }
    }
    #[test]
    fn test_subshell_with_variable_assignment() {
        let input = "(VAR=value; echo $VAR)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List {
                        statements,
                        operators,
                    } => {
                        assert_eq!(statements.len(), 2);
                        assert_eq!(operators.len(), 1);
                        assert_eq!(operators[0], ";");

                        // Check assignment
                        match &statements[0] {
                            Node::Assignment { name, value } => {
                                assert_eq!(name, "VAR");
                                match &**value {
                                    Node::StringLiteral(val) => {
                                        assert_eq!(val, "value");
                                    }
                                    _ => panic!("Expected StringLiteral node for value"),
                                }
                            }
                            _ => panic!("Expected Assignment node"),
                        }

                        // Check echo command
                        match &statements[1] {
                            Node::Command { name, args, .. } => {
                                assert_eq!(name, "echo");
                                assert_eq!(args, &["$VAR"]);
                            }
                            _ => panic!("Expected Command node"),
                        }
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_multiple_statements_mixed_operators() {
        let input = "(echo one; echo two && echo three || echo four)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List {
                        statements,
                        operators,
                    } => {
                        assert_eq!(statements.len(), 4);
                        assert_eq!(operators.len(), 3);
                        assert_eq!(operators[0], ";");
                        assert_eq!(operators[1], "&&");
                        assert_eq!(operators[2], "||");

                        // Check each command
                        for (i, expected) in ["one", "two", "three", "four"].iter().enumerate() {
                            match &statements[i] {
                                Node::Command { name, args, .. } => {
                                    assert_eq!(name, "echo");
                                    assert_eq!(args, &[*expected]);
                                }
                                _ => panic!("Expected Command node for echo {expected}"),
                            }
                        }
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_comments() {
        let input = "(
            # This is a comment
            echo hello
            # Another comment
            echo world
        )";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List { statements, .. } => {
                        // We should have 2 echo commands and possible comment nodes
                        let mut echo_count = 0;
                        let mut comment_count = 0;

                        for statement in statements {
                            match statement {
                                Node::Command { name, .. } if name == "echo" => {
                                    echo_count += 1;
                                }
                                Node::Comment(_) => {
                                    comment_count += 1;
                                }
                                _ => {}
                            }
                        }

                        assert_eq!(echo_count, 2, "Should have 2 echo commands");
                        // Comment handling varies, so we just check they're present
                        assert!(comment_count >= 0);
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_if_statement() {
        let input = "(if [ $x -eq 10 ]; then echo \"x is 10\"; fi)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List { statements, .. } => {
                        assert_eq!(statements.len(), 1);

                        // Check that we have an if statement inside
                        match &statements[0] {
                            Node::IfStatement {
                                condition,
                                consequence: _,
                                alternative,
                            } => {
                                // Verify it's an if statement, exact contents may vary
                                // based on your parser implementation
                                assert!(alternative.is_none());

                                // Just verify the basic structure is there
                                if let Node::Command { name, .. } = &**condition {
                                    assert_eq!(name, "[");
                                } else {
                                    // panic!("Expected Command node")
                                }
                            }
                            _ => panic!("Expected IfStatement node"),
                        }
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_subshell_with_function_definition() {
        let input = "(function greet() { echo \"Hello, $1!\"; })";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Subshell { list } => match &**list {
                    Node::List { statements, .. } => {
                        assert_eq!(statements.len(), 1);

                        // Check that we have a function definition inside
                        match &statements[0] {
                            Node::Function { name, .. } => {
                                assert_eq!(name, "greet");
                            }
                            _ => panic!("Expected Function node"),
                        }
                    }
                    _ => panic!("Expected List node inside subshell"),
                },
                _ => panic!("Expected Subshell node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_comment() {
        let input = "# This is a comment\necho hello";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 2);

                match &statements[0] {
                    Node::Comment(comment) => {
                        assert_eq!(comment, "# This is a comment");
                    }
                    _ => panic!("Expected Comment node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_simple_assignments() {
        let input = r#"
            #!/bin/bash
            # Script to process logs
            LOG_DIR="/var/log"
            OUTPUT=$(find $LOG_DIR -name "*.log" | grep error)
            LAST_ASSIGNMENT=1
        "#;

        let result = parse_test(input);
        assert_eq!(
            result,
            Node::List {
                statements: vec![
                    Node::Comment("#!/bin/bash".to_string()),
                    Node::Comment("# Script to process logs".to_string()),
                    Node::Assignment {
                        name: "LOG_DIR".to_string(),
                        value: Box::new(Node::StringLiteral("/var/log".to_string())),
                    },
                    Node::Assignment {
                        name: "OUTPUT".to_string(),
                        value: Box::new(Node::CommandSubstitution {
                            command: Box::new(Node::Pipeline {
                                commands: vec![
                                    Node::Command {
                                        name: "find".to_string(),
                                        args: vec![
                                            "$LOG_DIR".to_string(),
                                            "-name".to_string(),
                                            "*.log".to_string()
                                        ],
                                        redirects: vec![],
                                    },
                                    Node::Command {
                                        name: "grep".to_string(),
                                        args: vec!["error".to_string()],
                                        redirects: vec![],
                                    },
                                ],
                            }),
                        }),
                    },
                    Node::Assignment {
                        name: "LAST_ASSIGNMENT".to_string(),
                        value: Box::new(Node::StringLiteral("1".to_string())),
                    },
                ],
                operators: vec![
                    "\n".to_string(),
                    "\n".to_string(),
                    "\n".to_string(),
                    "\n".to_string(),
                    "\n".to_string()
                ],
            }
        )
    }

    #[test]
    fn test_complex_script() {
        let input = r#"
#!/bin/bash
# Script to process logs
LOG_DIR="/var/log"
OUTPUT=$(find $LOG_DIR -name "*.log" | grep error)
if [ -n "$OUTPUT" ]; then
    echo "Found error logs" > results.txt
    cat $OUTPUT >> results.txt
else
    echo "No error logs found" > results.txt
fi
"#;
        let result = parse_test(input);

        // Just verify that the complex script parses without errors
        // and contains the expected top-level structure
        match result {
            Node::List { ref statements, .. } => {
                // Should have comments, assignments, and an if statement
                assert!(statements.len() >= 4);

                // Check that we have some assignments
                let has_assignment = statements
                    .iter()
                    .any(|stmt| matches!(stmt, Node::Assignment { .. }));
                assert!(has_assignment, "Should have at least one assignment");

                // Check that we have an if statement
                let has_if = statements
                    .iter()
                    .any(|stmt| matches!(stmt, Node::IfStatement { .. }));
                assert!(has_if, "Should have an if statement");
            }
            _ => panic!("Expected Node::List for complex script"),
        }
    }

    #[test]
    fn test_parse_function_declaration() {
        // Test the name() syntax
        let mut parser = create_parser("hello() { echo \"Hello, World!\"; }");
        let result = parser.parse_script();

        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);

            if let Node::Function { name, body } = &statements[0] {
                assert_eq!(name, "hello");

                if let Node::List {
                    statements,
                    operators: _,
                } = &**body
                {
                    assert_eq!(statements.len(), 1);
                    // assert_eq!(operators.len(), 0);

                    if let Node::Command { name, args, .. } = &statements[0] {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "Hello, World!");
                    } else {
                        panic!("Expected Command node in function body");
                    }
                } else {
                    panic!("Expected List node for function body");
                }
            } else {
                panic!("Expected Function node");
            }
        } else {
            panic!("Expected List node at top level");
        }
    }

    #[test]
    fn test_parse_function_keyword_declaration() {
        // Test the function keyword syntax
        let mut parser = create_parser("function greet { echo \"Greetings!\"; }");
        let result = parser.parse_script();

        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);

            if let Node::Function { name, body } = &statements[0] {
                assert_eq!(name, "greet");

                if let Node::List { statements, .. } = &**body {
                    assert_eq!(statements.len(), 1);

                    if let Node::Command { name, args, .. } = &statements[0] {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "Greetings!");
                    } else {
                        panic!("Expected Command node in function body");
                    }
                } else {
                    panic!("Expected List node for function body");
                }
            } else {
                panic!("Expected Function node");
            }
        } else {
            panic!("Expected List node at top level");
        }
    }

    #[test]
    fn test_parse_function_with_multiple_statements() {
        let mut parser = create_parser(
            "multi() { 
            echo \"First line\"
            echo \"Second line\"
            return 0
        }",
        );

        let result = parser.parse_script();

        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);

            if let Node::Function { name, body } = &statements[0] {
                assert_eq!(name, "multi");

                if let Node::List {
                    statements,
                    operators,
                } = &**body
                {
                    // The parser correctly parses "return 0" as a Return node
                    assert_eq!(statements.len(), 3); // echo, echo, return
                    assert_eq!(operators.len(), 3); // Three newlines

                    // Check first command
                    if let Node::Command { name, args, .. } = &statements[0] {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "First line");
                    } else {
                        panic!("Expected first Command node");
                    }

                    // Check second command
                    if let Node::Command { name, args, .. } = &statements[1] {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "Second line");
                    } else {
                        panic!("Expected second Command node");
                    }

                    // Check third statement (return 0)
                    if let Node::Return { value } = &statements[2] {
                        if let Some(value_node) = value {
                            if let Node::StringLiteral(val) = value_node.as_ref() {
                                assert_eq!(val, "0");
                            } else {
                                panic!("Expected StringLiteral value in Return node");
                            }
                        } else {
                            panic!("Expected Some value in Return node");
                        }
                    } else {
                        panic!("Expected Return node");
                    }
                } else {
                    panic!("Expected List node for function body");
                }
            } else {
                panic!("Expected Function node");
            }
        } else {
            panic!("Expected List node at top level");
        }
    }

    // #[test]
    // fn test_parse_function_call() {
    //     let mut parser = create_parser("greet \"Hello World\"");
    //     let result = parser.parse_script();

    //     if let Node::List { statements, .. } = result {
    //         assert_eq!(statements.len(), 1);

    //         // This should be detected as a function call
    //         if let Node::FunctionCall { name, args } = &statements[0] {
    //             assert_eq!(name, "greet");
    //             assert_eq!(args.len(), 1);
    //             assert_eq!(args[0], "Hello World");
    //         } else {
    //             panic!("Expected FunctionCall node");
    //         }
    //     } else {
    //         panic!("Expected List node at top level");
    //     }
    // }

    // #[test]
    // fn test_parse_multiple_functions() {
    //     let mut parser = create_parser("
    //         hello() { echo \"Hello\"; }
    //         function goodbye { echo \"Goodbye\"; }

    //         # Call the functions
    //         hello
    //         goodbye
    //     ");

    //     let result = parser.parse_script();

    //     if let Node::List { statements, .. } = result {
    //         assert_eq!(statements.len(), 4, "Expected 4 statements: 2 function definitions and 2 function calls");

    //         // First function
    //         if let Node::Function { name, .. } = &statements[0] {
    //             assert_eq!(name, "hello");
    //         } else {
    //             panic!("Expected first Function node");
    //         }

    //         // Second function
    //         if let Node::Function { name, .. } = &statements[1] {
    //             assert_eq!(name, "goodbye");
    //         } else {
    //             panic!("Expected second Function node");
    //         }

    //         // First function call
    //         if let Node::FunctionCall { name, args } = &statements[2] {
    //             assert_eq!(name, "hello");
    //             assert_eq!(args.len(), 0);
    //         } else {
    //             panic!("Expected hello function call");
    //         }

    //         // Second function call
    //         if let Node::FunctionCall { name, args } = &statements[3] {
    //             assert_eq!(name, "goodbye");
    //             assert_eq!(args.len(), 0);
    //         } else {
    //             panic!("Expected goodbye function call");
    //         }
    //     } else {
    //         panic!("Expected List node at top level");
    //     }
    // }

    #[test]
    fn test_function_with_redirections() {
        let mut parser = create_parser("log() { echo \"Logging info\" > /tmp/log.txt; }");
        let result = parser.parse_script();

        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);

            if let Node::Function { name, body } = &statements[0] {
                assert_eq!(name, "log");

                if let Node::List { statements, .. } = &**body {
                    assert_eq!(statements.len(), 1);

                    if let Node::Command {
                        name,
                        args,
                        redirects,
                    } = &statements[0]
                    {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "Logging info");

                        // Check redirection
                        assert_eq!(redirects.len(), 1);
                        assert_eq!(redirects[0].file, "/tmp/log.txt");
                        assert!(matches!(redirects[0].kind, RedirectKind::Output));
                    } else {
                        panic!("Expected Command node with redirection");
                    }
                } else {
                    panic!("Expected List node for function body");
                }
            } else {
                panic!("Expected Function node");
            }
        } else {
            panic!("Expected List node at top level");
        }
    }

    #[test]
    fn test_function_with_pipeline() {
        let mut parser =
            create_parser("process_data() { cat file.txt | grep \"pattern\" | sort; }");
        let result = parser.parse_script();

        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);

            if let Node::Function { name, body } = &statements[0] {
                assert_eq!(name, "process_data");

                if let Node::List { statements, .. } = &**body {
                    assert_eq!(statements.len(), 1);

                    // Check that the body contains a pipeline
                    if let Node::Pipeline { commands } = &statements[0] {
                        assert_eq!(commands.len(), 3);

                        // Check first command - cat
                        if let Node::Command { name, args, .. } = &commands[0] {
                            assert_eq!(name, "cat");
                            assert_eq!(args.len(), 1);
                            assert_eq!(args[0], "file.txt");
                        } else {
                            panic!("Expected Command node for cat");
                        }

                        // Check second command - grep
                        if let Node::Command { name, args, .. } = &commands[1] {
                            assert_eq!(name, "grep");
                            assert_eq!(args.len(), 1);
                            assert_eq!(args[0], "pattern");
                        } else {
                            panic!("Expected Command node for grep");
                        }

                        // Check third command - sort
                        if let Node::Command { name, args, .. } = &commands[2] {
                            assert_eq!(name, "sort");
                            assert_eq!(args.len(), 0);
                        } else {
                            panic!("Expected Command node for sort");
                        }
                    } else {
                        panic!("Expected Pipeline node in function body");
                    }
                } else {
                    panic!("Expected List node for function body");
                }
            } else {
                panic!("Expected Function node");
            }
        } else {
            panic!("Expected List node at top level");
        }
    }

    #[test]
    fn test_function_with_variable_assignment() {
        let mut parser = create_parser("setup() { name=\"value\"; echo $name; }");
        let result = parser.parse_script();

        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);

            if let Node::Function { name, body } = &statements[0] {
                assert_eq!(name, "setup");

                if let Node::List { statements, .. } = &**body {
                    assert_eq!(statements.len(), 2);

                    // Check variable assignment
                    if let Node::Assignment { name, value } = &statements[0] {
                        assert_eq!(name, "name");

                        if let Node::StringLiteral(val) = &**value {
                            assert_eq!(val, "value");
                        } else {
                            panic!("Expected StringLiteral for value");
                        }
                    } else {
                        panic!("Expected Assignment node");
                    }

                    // Check echo command
                    if let Node::Command { name, args, .. } = &statements[1] {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "$name");
                    } else {
                        panic!("Expected Command node");
                    }
                } else {
                    panic!("Expected List node for function body");
                }
            } else {
                panic!("Expected Function node");
            }
        } else {
            panic!("Expected List node at top level");
        }
    }

    #[test]
    fn test_for_loop() {
        let input = r#"
for i in 1 2 3 4 5; do
    echo "Number: $i"
done
"#;

        // This would require additional parsing logic not present in the current code
        // Just verify it doesn't panic
        let _result = parse_test(input);
    }

    #[test]
    fn test_while_loop() {
        let input = "while [ $i -lt 5 ]; do echo $i; done";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::WhileLoop { condition, body } => {
                        // Verify condition is parsed
                        match condition.as_ref() {
                            Node::Command { name, args, .. } => {
                                assert_eq!(name, "[");
                                assert_eq!(args, &["$i", "-lt", "5", "]"]);
                            }
                            _ => panic!("Expected Command node for condition"),
                        }
                        // Verify body is parsed
                        match body.as_ref() {
                            Node::List { statements, .. } => {
                                assert_eq!(statements.len(), 1);
                                match &statements[0] {
                                    Node::Command { name, args, .. } => {
                                        assert_eq!(name, "echo");
                                        assert_eq!(args, &["$i"]);
                                    }
                                    _ => panic!("Expected Command node in body"),
                                }
                            }
                            _ => panic!("Expected List node for body"),
                        }
                    }
                    _ => panic!("Expected WhileLoop node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_until_loop() {
        let input = "until [ $i -ge 5 ]; do echo $i; done";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::UntilLoop { condition, body } => {
                        // Verify condition is parsed
                        match condition.as_ref() {
                            Node::Command { name, args, .. } => {
                                assert_eq!(name, "[");
                                assert_eq!(args, &["$i", "-ge", "5", "]"]);
                            }
                            _ => panic!("Expected Command node for condition"),
                        }
                        // Verify body is parsed
                        match body.as_ref() {
                            Node::List { statements, .. } => {
                                assert_eq!(statements.len(), 1);
                                match &statements[0] {
                                    Node::Command { name, args, .. } => {
                                        assert_eq!(name, "echo");
                                        assert_eq!(args, &["$i"]);
                                    }
                                    _ => panic!("Expected Command node in body"),
                                }
                            }
                            _ => panic!("Expected List node for body"),
                        }
                    }
                    _ => panic!("Expected UntilLoop node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_while_loop_multiline() {
        let input = r#"
while [ $count -lt 3 ]
do
    echo "Count: $count"
    count=$((count + 1))
done
"#;
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::WhileLoop { condition, body } => {
                        // Verify condition
                        match condition.as_ref() {
                            Node::Command { name, args, .. } => {
                                assert_eq!(name, "[");
                                assert_eq!(args, &["$count", "-lt", "3", "]"]);
                            }
                            _ => panic!("Expected Command node for condition"),
                        }
                        // Verify body has multiple statements
                        match body.as_ref() {
                            Node::List { statements, .. } => {
                                assert_eq!(statements.len(), 2);
                            }
                            _ => panic!("Expected List node for body"),
                        }
                    }
                    _ => panic!("Expected WhileLoop node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_nested_command_substitution() {
        let input = r#"echo $(echo $(date))"#;
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                match &statements[0] {
                    Node::Command { name, .. } => {
                        assert_eq!(name, "echo");
                        // Additional validation would be complex
                    }
                    _ => panic!("Expected Command node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_here_document() {
        let input = r#"cat << EOF
This is a multi-line
here document
EOF"#;

        let result = parse_test(input);
        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::Command {
                        name,
                        args,
                        redirects,
                    } => {
                        assert_eq!(name, "cat");
                        assert!(args.is_empty());
                        assert_eq!(redirects.len(), 1);
                        assert!(matches!(redirects[0].kind, RedirectKind::HereDoc));
                        assert!(redirects[0].file.contains("This is a multi-line"));
                        assert!(redirects[0].file.contains("here document"));
                    }
                    _ => panic!("Expected Command node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_here_document_no_space_delimiter_not_parsed_as_command() {
        let input = r#"cat <<EOF
alpha
beta
EOF"#;

        let result = parse_test(input);
        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::Command { name, redirects, .. } => {
                        assert_eq!(name, "cat");
                        assert_eq!(redirects.len(), 1);
                        assert!(matches!(redirects[0].kind, RedirectKind::HereDoc));
                        assert_eq!(redirects[0].file, "alpha\nbeta\n");
                    }
                    _ => panic!("Expected Command node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_background_execution() {
        let input = "long_running_command &";
        let result = parse_test(input);

        match result {
            Node::List { operators, .. } => {
                assert_eq!(operators.len(), 1);
                assert_eq!(operators[0], "&");
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_redirect_with_file_descriptor() {
        let input = "command 2>&1";
        let result = parse_test(input);
        match result {
            Node::Command {
                name,
                args,
                redirects,
            } => {
                assert_eq!(name, "command");
                assert!(args.is_empty());
                assert_eq!(redirects.len(), 1);
                assert_eq!(redirects[0].fd, Some(2));
                assert!(matches!(redirects[0].kind, RedirectKind::OutputDup));
                assert_eq!(redirects[0].file, "&1");
            }
            _ => panic!("Expected Command node"),
        }
    }

    #[test]
    fn test_redirect_to_dev_null() {
        let input = "command > /dev/null 2>&1";

        // This would require additional parsing logic not present in the current code
        // Just verify it doesn't panic
        let _result = parse_test(input);
    }

    #[test]
    fn test_redirect_to_dev_null_without_space_after_fd() {
        let input = "cat /sys/class/dmi/id/board_name 2>/dev/null";
        let result = parse_test(input);
        match result {
            Node::Command {
                name,
                args,
                redirects,
            } => {
                assert_eq!(name, "cat");
                assert_eq!(args, vec!["/sys/class/dmi/id/board_name"]);
                assert_eq!(redirects.len(), 1);
                assert_eq!(redirects[0].fd, Some(2));
                assert!(matches!(redirects[0].kind, RedirectKind::Output));
                assert_eq!(redirects[0].file, "/dev/null");
            }
            _ => panic!("Expected Command node"),
        }
    }

    #[test]
    fn test_brace_expansion() {
        let input = "echo file{1,2,3}.txt";

        // This would require additional lexing/parsing logic
        // Just verify it doesn't panic
        let _result = parse_test(input);
    }

    #[test]
    fn test_process_substitution() {
        let input = "diff <(sort file1) <(sort file2)";

        // This would require additional parsing logic not present in the current code
        // Just verify it doesn't panic
        let _result = parse_test(input);
    }

    #[test]
    fn test_arithmetic_expansion() {
        let input = "echo $((1 + 2 * 3))";

        // This would require additional parsing logic not present in the current code
        // Just verify it doesn't panic
        let _result = parse_test(input);
    }

    #[test]
    fn test_tilde_expansion() {
        let input = "ls ~/Documents";

        // Just verify it doesn't panic
        let _result = parse_test(input);
    }

    #[test]
    fn test_parameter_expansion() {
        let input = r#"echo ${VAR:-default} ${VAR##*/}"#;

        // This would require additional parsing logic not present in the current code
        // Just verify it doesn't panic
        let _result = parse_test(input);
    }

    #[test]
    fn test_glob_pattern() {
        let input = "ls *.rs";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "ls");
                    assert_eq!(args, &["*.rs"]);
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_case_statement() {
        let input = r#"
case "$1" in
    start)
        echo "Starting..."
        ;;
    stop)
        echo "Stopping..."
        ;;
    *)
        echo "Unknown command"
        ;;
esac
"#;

        // This would require additional parsing logic not present in the current code
        // Just verify it doesn't panic
        let _result = parse_test(input);
    }

    #[test]
    fn test_variable_assignment() {
        let input = "VAR=value";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);

                match &statements[0] {
                    Node::Assignment { name, value } => {
                        assert_eq!(name, "VAR");
                        match &**value {
                            Node::StringLiteral(val) => {
                                assert_eq!(val, "value");
                            }
                            _ => panic!("Expected StringLiteral node"),
                        }
                    }
                    _ => panic!("Expected Assignment node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_command_substitution_assignment() {
        let input = "OUTPUT=$(echo hello)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);

                match &statements[0] {
                    Node::Assignment { name, value } => {
                        assert_eq!(name, "OUTPUT");
                        match &**value {
                            Node::CommandSubstitution { command } => match &**command {
                                Node::Command { name, args, .. } => {
                                    assert_eq!(name, "echo");
                                    assert_eq!(args, &["hello"]);
                                }
                                _ => panic!("Expected Command node inside substitution"),
                            },
                            _ => panic!("Expected CommandSubstitution node"),
                        }
                    }
                    _ => panic!("Expected Assignment node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_command_substitution_complex() {
        let input = "OUTPUT=$(ls -la | grep .rs)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);

                match &statements[0] {
                    Node::Assignment { name, value } => {
                        assert_eq!(name, "OUTPUT");
                        match &**value {
                            Node::CommandSubstitution { command } => match &**command {
                                Node::Pipeline { commands } => {
                                    assert_eq!(commands.len(), 2);
                                }
                                _ => panic!("Expected Pipeline node inside substitution"),
                            },
                            _ => panic!("Expected CommandSubstitution node"),
                        }
                    }
                    _ => panic!("Expected Assignment node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_append_redirect() {
        let input = "echo 'appending' >> log.txt";
        let result = parse_test(input);

        // Checking the exact structure
        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);

                match &statements[0] {
                    Node::Command {
                        name,
                        args,
                        redirects,
                    } => {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1); // 'appending'
                        assert_eq!(redirects.len(), 1);
                        assert!(matches!(redirects[0].kind, RedirectKind::Append));
                        assert_eq!(redirects[0].file, "log.txt");
                    }
                    _ => panic!("Expected Command node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_question_extglob() {
        let input = "ls ?(file1|file2).txt";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "ls");
                    assert_eq!(args[0], "?(file1|file2).txt");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_star_extglob() {
        let input = "ls *(file1|file2).txt";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "ls");
                    assert_eq!(args[0], "*(file1|file2).txt");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_plus_extglob() {
        let input = "ls +(file1|file2).txt";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "ls");
                    assert_eq!(args[0], "+(file1|file2).txt");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_at_extglob() {
        let input = "ls @(file1|file2).txt";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "ls");
                    assert_eq!(args[0], "@(file1|file2).txt");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_not_extglob() {
        let input = "ls !(file1|file2).txt";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "ls");
                    assert_eq!(args[0], "!(file1|file2).txt");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_multiple_extglobs() {
        let input = "find . -name ?(*.txt|*.log) -o -name +(*.md|*.rst)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "find");
                    assert_eq!(args[0], ".");
                    assert_eq!(args[1], "-name");
                    assert_eq!(args[2], "?(*.txt|*.log)");
                    assert_eq!(args[3], "-o");
                    assert_eq!(args[4], "-name");
                    assert_eq!(args[5], "+(*.md|*.rst)");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_nested_extglobs() {
        let input = "ls +(!(file1|file2)|file3).txt";
        let result = parse_test(input);

        // This test might require more complex parsing logic for nested patterns
        // For now, just verify that parsing doesn't panic
        // In a more complete implementation, we would verify the exact pattern structure
        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, .. } => {
                    assert_eq!(name, "ls");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_extglob_in_pipeline() {
        let input = "ls ?(file1|file2).txt | grep pattern";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Pipeline { commands } => {
                    assert_eq!(commands.len(), 2);

                    match &commands[0] {
                        Node::Command { name, args, .. } => {
                            assert_eq!(name, "ls");
                            assert_eq!(args[0], "?(file1|file2).txt");
                        }
                        _ => panic!("Expected Command node for first pipeline command"),
                    }

                    match &commands[1] {
                        Node::Command { name, args, .. } => {
                            assert_eq!(name, "grep");
                            assert_eq!(args[0], "pattern");
                        }
                        _ => panic!("Expected Command node for second pipeline command"),
                    }
                }
                _ => panic!("Expected Pipeline node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_extglob_in_redirection() {
        let input = "cat <(grep pattern ?(file1|file2).txt)";

        // This test might require additional parsing logic for process substitution
        // Just verify it doesn't panic for now
        let _result = parse_test(input);
    }

    #[test]
    fn test_extglob_in_variable_assignment() {
        let input = "FILES=?(*.txt|*.log)";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Assignment { name, value: _ } => {
                    assert_eq!(name, "FILES");
                    // Check value based on how we're handling this in the implementation
                }
                _ => panic!("Expected Assignment node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_embedded_quotes() {
        let input = r#"echo "He said 'hello'""#;
        let result = parse_test(input);

        // The current lexer might not handle quotes properly, so adjust test expectations
        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);

                match &statements[0] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "echo");
                        // Either it will be a single argument or it might be split, check for both cases
                        if args.len() == 1 {
                            assert!(args[0].contains("He") && args[0].contains("hello"));
                        } else {
                            // Just verify that the command is recognized correctly
                            assert_eq!(name, "echo");
                        }
                    }
                    _ => panic!("Expected Command node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_logical_operators() {
        let input = "grep pattern file.txt && echo 'Found' || echo 'Not found'";
        let result = parse_test(input);

        match result {
            Node::List {
                statements: _,
                operators,
            } => {
                // Just check that the operators are recognized
                assert!(operators.contains(&"&&".to_string()));
                assert!(operators.contains(&"||".to_string()));
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_multiple_variable_assignments() {
        let input = "VAR1=value1 VAR2=value2 command arg1 arg2";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 3);

                // Check first assignment
                match &statements[0] {
                    Node::Assignment { name, value } => {
                        assert_eq!(name, "VAR1");
                        match &**value {
                            Node::StringLiteral(val) => {
                                assert_eq!(val, "value1");
                            }
                            _ => panic!("Expected StringLiteral node for VAR1"),
                        }
                    }
                    _ => panic!("Expected Assignment node for VAR1"),
                }

                // Check second assignment
                match &statements[1] {
                    Node::Assignment { name, value } => {
                        assert_eq!(name, "VAR2");
                        match &**value {
                            Node::StringLiteral(val) => {
                                assert_eq!(val, "value2");
                            }
                            _ => panic!("Expected StringLiteral node for VAR2"),
                        }
                    }
                    _ => panic!("Expected Assignment node for VAR2"),
                }

                // Check command
                match &statements[2] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "command");
                        assert_eq!(args, &["arg1", "arg2"]);
                    }
                    _ => panic!("Expected Command node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_variable_assignments_without_command() {
        let input = "VAR1=value1 VAR2=value2";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                // Multiple assignments should be handled as separate statements
                assert_eq!(statements.len(), 2);

                // Check first assignment
                match &statements[0] {
                    Node::Assignment { name, value } => {
                        assert_eq!(name, "VAR1");
                        match &**value {
                            Node::StringLiteral(val) => {
                                assert_eq!(val, "value1");
                            }
                            _ => panic!("Expected StringLiteral node for VAR1"),
                        }
                    }
                    _ => panic!("Expected Assignment node for VAR1"),
                }

                // Check second assignment
                match &statements[1] {
                    Node::Assignment { name, value } => {
                        assert_eq!(name, "VAR2");
                        match &**value {
                            Node::StringLiteral(val) => {
                                assert_eq!(val, "value2");
                            }
                            _ => panic!("Expected StringLiteral node for VAR2"),
                        }
                    }
                    _ => panic!("Expected Assignment node for VAR2"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }
    #[test]
    fn test_if_statement() {
        let input = r#"
if [ "$1" = "test" ]; then
    echo "This is a test"
else
    echo "This is not a test"
fi
"#;
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);
        let result = parser.parse_script();

        // We expect the Node::List with a single IfStatement inside
        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);

            if let Node::IfStatement {
                condition,
                consequence,
                alternative,
            } = &statements[0]
            {
                // Check the condition contains a test command
                if let Node::Command { name, args, .. } = &**condition {
                    assert_eq!(name, "[");
                    assert_eq!(args.len(), 4);
                    assert_eq!(args[0], "$1");
                    assert_eq!(args[1], "=");
                    assert_eq!(args[2], "test");
                    assert_eq!(args[3], "]");
                } else {
                    panic!("Expected condition to be a Command node {condition:?}");
                }

                // Check the consequence contains an echo command
                if let Node::List { statements, .. } = &**consequence {
                    assert_eq!(statements.len(), 1);
                    if let Node::Command { name, args, .. } = &statements[0] {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "This is a test");
                    } else {
                        panic!("Expected consequence command to be an echo command");
                    }
                } else {
                    panic!("Expected consequence to be a List node");
                }

                // Check the alternative contains an echo command
                if let Some(alt) = alternative {
                    if let Node::ElseBranch {
                        consequence: else_consequence,
                    } = &**alt
                    {
                        if let Node::List { statements, .. } = &**else_consequence {
                            assert_eq!(statements.len(), 1);
                            if let Node::Command { name, args, .. } = &statements[0] {
                                assert_eq!(name, "echo");
                                assert_eq!(args.len(), 1);
                                assert_eq!(args[0], "This is not a test");
                            } else {
                                panic!("Expected else block to contain an echo command");
                            }
                        } else {
                            panic!("Expected else consequence to be a List node");
                        }
                    } else {
                        panic!("Expected alternative to be an ElseBranch node");
                    }
                } else {
                    panic!("Expected if statement to have an else branch");
                }
            } else {
                panic!("Expected script to contain an IfStatement node");
            }
        } else {
            panic!("Expected parser output to be a List node");
        }
    }

    #[test]
    fn test_if_elif_else_statement() {
        let input = r#"
if [ "$1" = "test1" ]; then
    echo "This is test1"
elif [ "$1" = "test2" ]; then
    echo "This is test2"
else
    echo "This is neither test1 nor test2"
fi
"#;
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);
        let result = parser.parse_script();

        // Verify that we get a List node with an IfStatement
        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);

            if let Node::IfStatement {
                condition,
                consequence,
                alternative,
            } = &statements[0]
            {
                // Check first condition (if)
                if let Node::Command { name, args, .. } = &**condition {
                    assert_eq!(name, "[");
                    assert_eq!(args.len(), 4);
                    assert_eq!(args[0], "$1");
                    assert_eq!(args[1], "=");
                    assert_eq!(args[2], "test1");
                    assert_eq!(args[3], "]");
                } else {
                    panic!("Expected condition to be a Command node");
                }

                // Check first consequence (then block)
                if let Node::List { statements, .. } = &**consequence {
                    assert_eq!(statements.len(), 1);
                    if let Node::Command { name, args, .. } = &statements[0] {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "This is test1");
                    } else {
                        panic!("Expected 'then' block to contain an echo command");
                    }
                } else {
                    panic!("Expected 'then' consequence to be a List node");
                }

                // Check the elif and else branches
                if let Some(alt) = alternative {
                    // The alternative should be either an ElifBranch (simple case) or IfStatement (with else)
                    match &**alt {
                        Node::ElifBranch {
                            condition: elif_condition,
                            consequence: elif_consequence,
                        } => {
                            // Check elif condition
                            if let Node::Command { name, args, .. } = &**elif_condition {
                                assert_eq!(name, "[");
                                assert_eq!(args.len(), 4);
                                assert_eq!(args[0], "$1");
                                assert_eq!(args[1], "=");
                                assert_eq!(args[2], "test2");
                                assert_eq!(args[3], "]");
                            } else {
                                panic!("Expected elif condition to be a Command node");
                            }

                            // Check elif consequence
                            if let Node::List { statements, .. } = &**elif_consequence {
                                assert_eq!(statements.len(), 1);
                                if let Node::Command { name, args, .. } = &statements[0] {
                                    assert_eq!(name, "echo");
                                    assert_eq!(args.len(), 1);
                                    assert_eq!(args[0], "This is test2");
                                } else {
                                    panic!("Expected elif consequence to contain an echo command");
                                }
                            } else {
                                panic!("Expected elif consequence to be a List node");
                            }
                        }
                        Node::IfStatement {
                            condition: elif_condition,
                            consequence: elif_consequence,
                            alternative: else_alternative,
                        } => {
                            // This is the case when there's an else clause after elif
                            // Check elif condition
                            if let Node::Command { name, args, .. } = &**elif_condition {
                                assert_eq!(name, "[");
                                assert_eq!(args.len(), 4);
                                assert_eq!(args[0], "$1");
                                assert_eq!(args[1], "=");
                                assert_eq!(args[2], "test2");
                                assert_eq!(args[3], "]");
                            } else {
                                panic!("Expected elif condition to be a Command node");
                            }

                            // Check elif consequence
                            if let Node::List { statements, .. } = &**elif_consequence {
                                assert_eq!(statements.len(), 1);
                                if let Node::Command { name, args, .. } = &statements[0] {
                                    assert_eq!(name, "echo");
                                    assert_eq!(args.len(), 1);
                                    assert_eq!(args[0], "This is test2");
                                } else {
                                    panic!("Expected elif consequence to contain an echo command");
                                }
                            } else {
                                panic!("Expected elif consequence to be a List node");
                            }

                            // Verify that there's an else branch
                            assert!(
                                else_alternative.is_some(),
                                "Expected else branch after elif"
                            );
                        }
                        _ => {
                            panic!(
                                "Expected alternative to be either ElifBranch or IfStatement node"
                            );
                        }
                    }
                } else {
                    panic!("Expected if statement to have an elif branch");
                }
            } else {
                panic!("Expected script to contain an IfStatement node");
            }
        } else {
            panic!("Expected parser output to be a List node");
        }
    }

    #[test]
    fn test_multiple_elif_statements() {
        let input = r#"
if [ "$1" = "test1" ]; then
    echo "This is test1"
elif [ "$1" = "test2" ]; then
    echo "This is test2"
elif [ "$1" = "test3" ]; then
    echo "This is test3"
else
    echo "Unknown test"
fi
"#;
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);
        let result = parser.parse_script();

        // Basic assertion that parsing completes without errors
        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);
            assert!(matches!(statements[0], Node::IfStatement { .. }));
        } else {
            panic!("Expected parser output to be a List node");
        }
    }

    #[test]
    fn test_if_without_else() {
        let input = r#"
if [ "$1" = "test" ]; then
    echo "This is a test"
fi
"#;
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);
        let result = parser.parse_script();

        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);

            if let Node::IfStatement {
                condition,
                consequence,
                alternative,
            } = &statements[0]
            {
                // Condition should be the test command
                assert!(matches!(**condition, Node::Command { .. }));

                // Consequence should be a List containing the echo command
                assert!(matches!(**consequence, Node::List { .. }));

                // There should be no alternative
                assert!(alternative.is_none());
            } else {
                panic!("Expected an IfStatement node");
            }
        } else {
            panic!("Expected parser output to be a List node");
        }
    }

    #[test]
    fn test_nested_if_statements() {
        let input = r#"
if [ "$1" = "outer" ]; then
    if [ "$2" = "inner" ]; then
        echo "Nested condition met"
    else
        echo "Outer condition met, inner not met"
    fi
else
    echo "Outer condition not met"
fi
"#;
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);
        let result = parser.parse_script();

        // Basic assertion that parsing completes without errors
        if let Node::List { statements, .. } = result {
            assert_eq!(statements.len(), 1);
            assert!(matches!(statements[0], Node::IfStatement { .. }));

            // Check that the outer if's consequence contains another if statement
            if let Node::IfStatement { consequence, .. } = &statements[0] {
                if let Node::List {
                    statements: inner_statements,
                    ..
                } = &**consequence
                {
                    assert!(
                        inner_statements
                            .iter()
                            .any(|node| matches!(node, Node::IfStatement { .. }))
                    );
                } else {
                    panic!("Expected outer if's consequence to be a List node");
                }
            }
        } else {
            panic!("Expected parser output to be a List node");
        }
    }

    #[test]
    fn test_example_parse_pkgbuild() {
        // Retired from https://gitlab.archlinux.org/archlinux/packaging/packages/rio/-/blob/main/PKGBUILD
        let content = "
    # Maintainer:  Orhun Parmaksız <orhun@archlinux.org>
    # Maintainer: Caleb Maclennan <caleb@alerque.com>
    # Contributor: bbx0 <39773919+bbx0@users.noreply.github.com>
    # Contributor: Raphael Amorim <rapha850@gmail.com>
    pkgname=rio
    pkgver=0.2.12
    pkgrel=1
    pkgdesc=\"A hardware-accelerated GPU terminal emulator powered by WebGPU\"
    arch=('x86_64')
    url=\"https://github.com/raphamorim/rio\"
    license=(\"MIT\")
    # https://raphamorim.io/rio/install/#arch-linux
    options=('!lto')
    depends=(
    'gcc-libs'
    'fontconfig'
    'freetype2'
    'glibc'
    'hicolor-icon-theme'
    )
    makedepends=(
    'cargo'
    'cmake'
    'desktop-file-utils'
    'libxcb'
    'libxkbcommon'
    'python'
    )
    source=(\"${pkgname}-${pkgver}.tar.gz::${url}/archive/refs/tags/v${pkgver}.tar.gz\")
    sha512sums=('2a73567a591b93707a35e1658572fb48cd8dbeda4cf4418de5887183b0c90c93213b6f15ff47a50b9aaaccd295e185ebcfb594847d7ef8c9e91293740a78c493')
    prepare() {
    cd \"${pkgname}-${pkgver}\"
    cargo fetch --locked --target \"$(rustc -vV | sed -n 's/host: //p')\"
    }
    build() {
    cd \"${pkgname}-${pkgver}\"
    cargo build --frozen --release --all-features
    }
    check() {
    cd \"${pkgname}-${pkgver}\"
    cargo test --frozen --workspace
    }
    package() {
    cd \"${pkgname}-${pkgver}\"
    install -Dm0755 -t \"${pkgdir}/usr/bin/\" \"target/release/${pkgname}\"
    install -Dm0644 -t \"${pkgdir}/usr/share/doc/${pkgname}/\" \"README.md\"
    install -Dm0644 -t \"${pkgdir}/usr/share/licenses/${pkgname}/\" \"LICENSE\"
    desktop-file-install -m 644 --dir \"${pkgdir}/usr/share/applications/\" \"misc/${pkgname}.desktop\"
    install -Dm0644 \"docs/static/assets/${pkgname}-logo.svg\" \"$pkgdir/usr/share/icons/hicolor/scalable/apps/${pkgname}.svg\"
    }
    # vim: ts=2 sw=2 et:
    ";

        // Create a lexer for the content
        let lexer = Lexer::new(content);

        // Create a parser with the lexer
        let mut parser = Parser::new(lexer);

        // Parse the entire script
        let ast = parser.parse_script();

        // Expected structure (high-level)
        // 1. Multiple comment nodes
        // 2. Multiple variable assignments (pkgname, pkgver, etc.)
        // 3. Function definitions (prepare, build, check, package)

        // Verify the structure is a List node containing statements
        if let Node::List {
            statements,
            operators: _,
        } = ast
        {
            // Check that we have the expected number of function definitions (4)
            let function_count = statements
                .iter()
                .filter(|node| matches!(node, Node::Function { .. }))
                .count();
            assert_eq!(function_count, 4, "Expected 4 function definitions");

            // Check that we have assignment nodes for package variables
            let pkgname_assignment = statements.iter().find(|node| {
                if let Node::Assignment { name, .. } = node {
                    name == "pkgname"
                } else {
                    false
                }
            });
            assert!(pkgname_assignment.is_some(), "pkgname assignment not found");

            // Verify the prepare function content
            if let Some(prepare_fn) = statements.iter().find(|node| {
                if let Node::Function { name, .. } = node {
                    name == "prepare"
                } else {
                    false
                }
            }) {
                if let Node::Function { name, body } = prepare_fn {
                    assert_eq!(name, "prepare", "Function name should be 'prepare'");

                    // Check that the function body contains a cd command followed by cargo fetch
                    if let Node::List {
                        statements: fn_statements,
                        ..
                    } = body.as_ref()
                    {
                        assert!(
                            fn_statements.len() >= 2,
                            "prepare function should have at least 2 statements"
                        );

                        // Check for cd command
                        if let Some(Node::Command { name, .. }) = fn_statements.first() {
                            assert_eq!(name, "cd", "First command in prepare should be 'cd'");
                        } else {
                            panic!("First statement in prepare should be a cd command");
                        }

                        // Check for cargo fetch command
                        if let Some(Node::Command { name, .. }) = fn_statements.get(1) {
                            assert_eq!(
                                name, "cargo",
                                "Second command in prepare should be 'cargo'"
                            );
                        } else {
                            panic!("Second statement in prepare should be a cargo command");
                        }
                    } else {
                        panic!("Function body should be a List node");
                    }
                } else {
                    panic!("Expected prepare to be a Function node");
                }
            } else {
                panic!("prepare function not found");
            }

            // Verify the package function which contains variable references in commands
            if let Some(package_fn) = statements.iter().find(|node| {
                if let Node::Function { name, .. } = node {
                    name == "package"
                } else {
                    false
                }
            }) {
                if let Node::Function { name, body } = package_fn {
                    assert_eq!(name, "package", "Function name should be 'package'");

                    // Check the contents of the package function
                    if let Node::List {
                        statements: fn_statements,
                        ..
                    } = body.as_ref()
                    {
                        // Check for install commands
                        let install_commands = fn_statements.iter().filter(|node| {
                            matches!(node, Node::Command { name, .. } if name == "install")
                        }).count();

                        // There should be several install commands in the package function
                        assert!(
                            install_commands >= 3,
                            "Expected at least 3 install commands in package function"
                        );

                        // Check for commands that use variable references
                        let commands_with_vars = fn_statements
                            .iter()
                            .filter(|node| {
                                if let Node::Command { args, .. } = node {
                                    args.iter().any(|arg| {
                                        arg.contains("${pkgname}") || arg.contains("$pkgdir")
                                    })
                                } else {
                                    false
                                }
                            })
                            .count();

                        // Verify that we have commands using variables
                        assert!(
                            commands_with_vars > 0,
                            "Expected commands using variables in package function"
                        );
                    }
                }
            } else {
                panic!("package function not found");
            }

            println!("Test passed successfully!");
        } else {
            panic!("Expected AST root to be a List node");
        }
    }

    #[test]
    fn test_simple_array_assignment() {
        let input = "fruits=('apple' 'banana' 'orange')";
        let mut parser = create_parser(input);

        let node = parser.parse_statement().unwrap();

        match node {
            Node::Assignment { name, value } => {
                assert_eq!(name, "fruits");
                match *value {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 3);
                        assert_eq!(elements[0], "apple");
                        assert_eq!(elements[1], "banana");
                        assert_eq!(elements[2], "orange");
                    }
                    _ => panic!("Expected Node::Array, got something else"),
                }
            }
            _ => panic!("Expected Node::Assignment, got something else"),
        }
    }

    #[test]
    fn test_empty_array_assignment() {
        let input = "empty_array=()";
        let mut parser = create_parser(input);

        let node = parser.parse_statement().unwrap();

        match node {
            Node::Assignment { name, value } => {
                assert_eq!(name, "empty_array");
                match *value {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 0);
                    }
                    _ => panic!("Expected Node::Array, got something else"),
                }
            }
            _ => panic!("Expected Node::Assignment, got something else"),
        }
    }

    #[test]
    fn test_array_with_double_quotes() {
        let input = r#"langs=("rust" "go" "python")"#;
        let mut parser = create_parser(input);

        let node = parser.parse_statement().unwrap();

        match node {
            Node::Assignment { name, value } => {
                assert_eq!(name, "langs");
                match *value {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 3);
                        assert_eq!(elements[0], "rust");
                        assert_eq!(elements[1], "go");
                        assert_eq!(elements[2], "python");
                    }
                    _ => panic!("Expected Node::Array, got something else"),
                }
            }
            _ => panic!("Expected Node::Assignment, got something else"),
        }
    }

    #[test]
    fn test_array_mixed_quotes() {
        let input = r#"mixed=('single' "double" unquoted)"#;
        let mut parser = create_parser(input);

        let node = parser.parse_statement().unwrap();

        match node {
            Node::Assignment { name, value } => {
                assert_eq!(name, "mixed");
                match *value {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 3);
                        assert_eq!(elements[0], "single");
                        assert_eq!(elements[1], "double");
                        assert_eq!(elements[2], "unquoted");
                    }
                    _ => panic!("Expected Node::Array, got something else"),
                }
            }
            _ => panic!("Expected Node::Assignment, got something else"),
        }
    }

    #[test]
    fn test_array_with_spaces() {
        let input = r#"spaced=( 'item 1'   "item 2"    'item 3' )"#;
        let mut parser = create_parser(input);

        let node = parser.parse_statement().unwrap();

        match node {
            Node::Assignment { name, value } => {
                assert_eq!(name, "spaced");
                match *value {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 3);
                        assert_eq!(elements[0], "item 1");
                        assert_eq!(elements[1], "item 2");
                        assert_eq!(elements[2], "item 3");
                    }
                    _ => panic!("Expected Node::Array, got something else"),
                }
            }
            _ => panic!("Expected Node::Assignment, got something else"),
        }
    }

    #[test]
    fn test_array_with_multiline() {
        let input = "multiline=(
            'line 1'
            \"line 2\"
            line3
        )";
        let mut parser = create_parser(input);

        let node = parser.parse_statement().unwrap();

        match node {
            Node::Assignment { name, value } => {
                assert_eq!(name, "multiline");
                match *value {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 3);
                        assert_eq!(elements[0], "line 1");
                        assert_eq!(elements[1], "line 2");
                        assert_eq!(elements[2], "line3");
                    }
                    _ => panic!("Expected Node::Array, got something else"),
                }
            }
            _ => panic!("Expected Node::Assignment, got something else"),
        }
    }

    #[test]
    fn test_multiple_array_assignments() {
        let input = "fruits=('apple' 'banana')\ncolors=('red' 'blue')";
        let mut parser = create_parser(input);

        // Parse first array assignment
        let node1 = parser.parse_statement().unwrap();

        match node1 {
            Node::Assignment { name, value } => {
                assert_eq!(name, "fruits");
                match *value {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 2);
                        assert_eq!(elements[0], "apple");
                        assert_eq!(elements[1], "banana");
                    }
                    _ => panic!("Expected Node::Array, got something else"),
                }
            }
            _ => panic!("Expected Node::Assignment, got something else"),
        }

        // Skip the newline token
        if let TokenKind::Newline = parser.current_token.kind {
            parser.next_token();
        }

        // Parse second array assignment
        let node2 = parser.parse_statement().unwrap();

        match node2 {
            Node::Assignment { name, value } => {
                assert_eq!(name, "colors");
                match *value {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 2);
                        assert_eq!(elements[0], "red");
                        assert_eq!(elements[1], "blue");
                    }
                    _ => panic!("Expected Node::Array, got something else"),
                }
            }
            _ => panic!("Expected Node::Assignment, got something else"),
        }
    }

    #[test]
    fn test_parse_full_script_with_arrays() {
        let input = "#!/bin/bash\n\n# Array definitions\nfruits=('apple' 'banana')\ncolors=('red' 'blue')\n\necho ${fruits[0]}";
        let mut parser = create_parser(input);

        let script_node = parser.parse_script();

        match script_node {
            Node::List {
                statements,
                operators: _,
            } => {
                // Should have at least 3 statements: two array assignments and one echo command
                assert!(statements.len() >= 3);

                // Check first array assignment (after potential comments)
                let mut found_fruits_array = false;
                let mut found_colors_array = false;

                for statement in statements {
                    if let Node::Assignment { name, value } = statement {
                        if name == "fruits" {
                            found_fruits_array = true;
                            match *value {
                                Node::Array { elements } => {
                                    assert_eq!(elements.len(), 2);
                                    assert_eq!(elements[0], "apple");
                                    assert_eq!(elements[1], "banana");
                                }
                                _ => panic!("Expected Node::Array for fruits, got something else"),
                            }
                        } else if name == "colors" {
                            found_colors_array = true;
                            match *value {
                                Node::Array { elements } => {
                                    assert_eq!(elements.len(), 2);
                                    assert_eq!(elements[0], "red");
                                    assert_eq!(elements[1], "blue");
                                }
                                _ => panic!("Expected Node::Array for colors, got something else"),
                            }
                        }
                    }
                }

                assert!(found_fruits_array, "Didn't find fruits array assignment");
                assert!(found_colors_array, "Didn't find colors array assignment");
            }
            _ => panic!("Expected Node::List for script, got something else"),
        }
    }

    #[test]
    fn test_array_in_function() {
        let input = "function setup() {\n  tools=('grep' 'awk' 'sed')\n  echo ${tools[0]}\n}";
        let mut parser = create_parser(input);

        let result = parser.parse_script();

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);

                match &statements[0] {
                    Node::Function { name, body } => {
                        assert_eq!(name, "setup");

                        match &**body {
                            Node::List {
                                statements,
                                operators: _,
                            } => {
                                let mut found_array = false;

                                for statement in statements {
                                    if let Node::Assignment { name, value } = statement {
                                        if name == "tools" {
                                            found_array = true;
                                            match &**value {
                                                Node::Array { elements } => {
                                                    assert_eq!(elements.len(), 3);
                                                    assert_eq!(elements[0], "grep");
                                                    assert_eq!(elements[1], "awk");
                                                    assert_eq!(elements[2], "sed");
                                                }
                                                _ => panic!(
                                                    "Expected Node::Array, got something else"
                                                ),
                                            }
                                        }
                                    }
                                }

                                assert!(found_array, "Didn't find tools array in function body");
                            }
                            _ => {
                                panic!("Expected Node::List for function body, got something else")
                            }
                        }
                    }
                    other => panic!("Expected Node::Function, got {other:?}"),
                }
            }
            other => panic!("Expected Node::List from parse_script, got {other:?}"),
        }
    }

    #[test]
    fn test_array_index_references() {
        // This test just ensures we can parse scripts with array index references,
        // even though the parser doesn't specifically handle them
        let input = "fruits=('apple' 'banana')\necho ${fruits[0]}";
        let mut parser = create_parser(input);

        // This should parse without errors
        let script_node = parser.parse_script();

        match script_node {
            Node::List {
                statements,
                operators: _,
            } => {
                // The parser might generate more statements due to parameter expansion handling
                assert!(statements.len() >= 2); // at least array assignment + echo command
            }
            _ => panic!("Expected Node::List, got something else"),
        }
    }

    #[test]
    fn test_export_without_assignment() {
        let input = "export PATH";
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "PATH");
                assert!(value.is_none());
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_with_string_assignment() {
        let input = "export PATH=/usr/bin";
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "PATH");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::StringLiteral(val) => assert_eq!(val, "/usr/bin"),
                    _ => panic!("Expected StringLiteral value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_with_quoted_string() {
        let input = r#"export MESSAGE="Hello World""#;
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "MESSAGE");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::StringLiteral(val) => assert_eq!(val, "Hello World"),
                    _ => panic!("Expected StringLiteral value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_with_single_quoted_string() {
        let input = "export MESSAGE='Hello World'";
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "MESSAGE");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::SingleQuotedString(val) => assert_eq!(val, "Hello World"),
                    _ => panic!("Expected SingleQuotedString value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_with_array_assignment() {
        let input = "export arch=('x86_64')";
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "arch");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 1);
                        assert_eq!(elements[0], "x86_64");
                    }
                    _ => panic!("Expected Array value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_with_multi_element_array() {
        let input = "export LANGS=('rust' 'python' 'javascript')";
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "LANGS");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 3);
                        assert_eq!(elements[0], "rust");
                        assert_eq!(elements[1], "python");
                        assert_eq!(elements[2], "javascript");
                    }
                    _ => panic!("Expected Array value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_with_quoted_array_elements() {
        let input = r#"export PATHS=("/usr/bin" "/usr/local/bin")"#;
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "PATHS");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 2);
                        assert_eq!(elements[0], "/usr/bin");
                        assert_eq!(elements[1], "/usr/local/bin");
                    }
                    _ => panic!("Expected Array value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_with_command_substitution() {
        let input = "export DATE=$(date)";
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "DATE");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::CommandSubstitution { command } => match *command {
                        Node::Command { name, args, .. } => {
                            assert_eq!(name, "date");
                            assert!(args.is_empty());
                        }
                        _ => panic!("Expected Command inside CommandSubstitution"),
                    },
                    _ => panic!("Expected CommandSubstitution value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_empty_array() {
        let input = "export EMPTY=()";
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "EMPTY");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 0);
                    }
                    _ => panic!("Expected Array value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_mixed_quoted_unquoted_array() {
        let input = r#"export MIXED=(unquoted "double quoted" 'single quoted')"#;
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "MIXED");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::Array { elements } => {
                        assert_eq!(elements.len(), 3);
                        assert_eq!(elements[0], "unquoted");
                        assert_eq!(elements[1], "double quoted");
                        assert_eq!(elements[2], "single quoted");
                    }
                    _ => panic!("Expected Array value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_with_empty_value() {
        let input = "export EMPTY=";
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "EMPTY");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::StringLiteral(val) => assert_eq!(val, ""),
                    _ => panic!("Expected StringLiteral value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_export_keyword_detection() {
        // Test that "export" is detected as a keyword when it starts a statement
        let input = "export VAR=value";
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { .. } => {
                // Success - export was properly detected
            }
            _ => panic!("Expected Export node, export keyword not detected"),
        }
    }

    #[test]
    fn test_multiple_exports_in_script() {
        let input = "export VAR1=value1\nexport VAR2=value2";
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_script();

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 2);

                // Check first export
                match &statements[0] {
                    Node::Export { name, value } => {
                        assert_eq!(name, "VAR1");
                        if let Some(val) = value {
                            match **val {
                                Node::StringLiteral(ref s) => assert_eq!(s, "value1"),
                                _ => panic!("Expected StringLiteral"),
                            }
                        }
                    }
                    _ => panic!("Expected Export node"),
                }

                // Check second export
                match &statements[1] {
                    Node::Export { name, value } => {
                        assert_eq!(name, "VAR2");
                        if let Some(val) = value {
                            match **val {
                                Node::StringLiteral(ref s) => assert_eq!(s, "value2"),
                                _ => panic!("Expected StringLiteral"),
                            }
                        }
                    }
                    _ => panic!("Expected Export node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_export_with_special_characters_in_value() {
        let input = r#"export SPECIAL="path/with-dashes_and.dots""#;
        let lexer = Lexer::new(input);
        let mut parser = Parser::new(lexer);

        let result = parser.parse_statement().unwrap();

        match result {
            Node::Export { name, value } => {
                assert_eq!(name, "SPECIAL");
                assert!(value.is_some());

                match *value.unwrap() {
                    Node::StringLiteral(val) => assert_eq!(val, "path/with-dashes_and.dots"),
                    _ => panic!("Expected StringLiteral value"),
                }
            }
            _ => panic!("Expected Export node, got {result:?}"),
        }
    }

    #[test]
    fn test_glob_patterns_in_commands() {
        // Test various glob patterns in command arguments
        let input = "ls *.txt file?.log [0-9]*.dat";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "ls");
                    assert_eq!(args.len(), 3);
                    assert_eq!(args[0], "*.txt");
                    assert_eq!(args[1], "file?.log");
                    assert_eq!(args[2], "[0-9]*.dat");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_glob_patterns_with_character_classes() {
        // Test character class patterns
        let input = "find file[abc].txt data[0-9].log test[!xyz].dat";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "find");
                    assert_eq!(args.len(), 3);
                    assert_eq!(args[0], "file[abc].txt");
                    assert_eq!(args[1], "data[0-9].log");
                    assert_eq!(args[2], "test[!xyz].dat");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_glob_patterns_in_conditionals() {
        // Test glob patterns in if statements
        let input = "if [ -f *.txt ]; then echo found; fi";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::IfStatement { condition, .. } => match condition.as_ref() {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "[");
                        assert_eq!(args.len(), 3);
                        assert_eq!(args[0], "-f");
                        assert_eq!(args[1], "*.txt");
                        assert_eq!(args[2], "]");
                    }
                    _ => panic!("Expected Command node in condition"),
                },
                _ => panic!("Expected IfStatement node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_glob_patterns_with_paths() {
        // Test glob patterns with directory paths
        let input = "cp /src/*.c ./dest/file?.h ../backup/[0-9]*.bak";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "cp");
                    assert_eq!(args.len(), 3);
                    assert_eq!(args[0], "/src/*.c");
                    assert_eq!(args[1], "./dest/file?.h");
                    assert_eq!(args[2], "../backup/[0-9]*.bak");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_complex_glob_patterns() {
        // Test complex glob patterns with multiple wildcards
        let input = "process *.[ch] *.{txt,log} file[0-9][a-z].*";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Command { name, args, .. } => {
                    assert_eq!(name, "process");
                    assert_eq!(args.len(), 3);
                    assert_eq!(args[0], "*.[ch]");
                    assert_eq!(args[1], "*.{txt,log}");
                    assert_eq!(args[2], "file[0-9][a-z].*");
                }
                _ => panic!("Expected Command node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_glob_patterns_in_variable_assignment() {
        // Test glob patterns in variable assignments
        let input = "files=*.txt";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => match &statements[0] {
                Node::Assignment { name, value } => {
                    assert_eq!(name, "files");
                    match value.as_ref() {
                        Node::StringLiteral(pattern) => {
                            assert_eq!(pattern, "*.txt");
                        }
                        _ => panic!("Expected StringLiteral in assignment value"),
                    }
                }
                _ => panic!("Expected Assignment node"),
            },
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_bash_style_conditional_and_parsing() {
        // Test parsing of [ condition ] && command
        let input = r#"[ "test" = "test" ] && echo "success""#;
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 2);
                assert_eq!(operators.len(), 1);
                assert_eq!(operators[0], "&&");

                // First statement should be the test command
                match &statements[0] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "[");
                        assert_eq!(args.len(), 4); // "test", "=", "test", "]"
                        assert_eq!(args[0], "test");
                        assert_eq!(args[1], "=");
                        assert_eq!(args[2], "test");
                        assert_eq!(args[3], "]");
                    }
                    _ => panic!("Expected Command node for test"),
                }

                // Second statement should be the echo command
                match &statements[1] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "success");
                    }
                    _ => panic!("Expected Command node for echo"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_bash_style_conditional_or_parsing() {
        // Test parsing of [ condition ] || command
        let input = r#"[ "test" != "other" ] || echo "failed""#;
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 2);
                assert_eq!(operators.len(), 1);
                assert_eq!(operators[0], "||");

                // First statement should be the test command
                match &statements[0] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "[");
                        assert_eq!(args.len(), 4); // "test", "!=", "other", "]"
                        assert_eq!(args[0], "test");
                        assert_eq!(args[1], "!=");
                        assert_eq!(args[2], "other");
                        assert_eq!(args[3], "]");
                    }
                    _ => panic!("Expected Command node for test"),
                }

                // Second statement should be the echo command
                match &statements[1] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "failed");
                    }
                    _ => panic!("Expected Command node for echo"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_bash_style_conditional_file_test_parsing() {
        // Test parsing of file test operators
        let input = r#"[ -s "/path/to/file" ] && . "/path/to/script""#;
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 2);
                assert_eq!(operators.len(), 1);
                assert_eq!(operators[0], "&&");

                // First statement should be the file test
                match &statements[0] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "[");
                        assert_eq!(args.len(), 3); // "-s", "/path/to/file", "]"
                        assert_eq!(args[0], "-s");
                        assert_eq!(args[1], "/path/to/file");
                        assert_eq!(args[2], "]");
                    }
                    _ => panic!("Expected Command node for file test"),
                }

                // Second statement should be the source command
                match &statements[1] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, ".");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "/path/to/script");
                    }
                    _ => panic!("Expected Command node for source"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_bash_style_conditional_with_variables_parsing() {
        // Test parsing with variable expansion
        let input = r#"[ -n "$HOME" ] && echo "HOME is set""#;
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 2);
                assert_eq!(operators.len(), 1);
                assert_eq!(operators[0], "&&");

                // First statement should be the variable test
                match &statements[0] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "[");
                        assert_eq!(args.len(), 3); // "-n", "$HOME", "]"
                        assert_eq!(args[0], "-n");
                        assert_eq!(args[1], "$HOME");
                        assert_eq!(args[2], "]");
                    }
                    _ => panic!("Expected Command node for variable test"),
                }

                // Second statement should be the echo command
                match &statements[1] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "HOME is set");
                    }
                    _ => panic!("Expected Command node for echo"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_bash_style_conditional_chaining_parsing() {
        // Test parsing of chained conditional operations
        let input = r#"[ "a" = "a" ] && echo "first" || echo "second""#;
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 3);
                assert_eq!(operators.len(), 2);
                assert_eq!(operators[0], "&&");
                assert_eq!(operators[1], "||");

                // First statement: test command
                match &statements[0] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "[");
                        assert_eq!(args[0], "a");
                        assert_eq!(args[1], "=");
                        assert_eq!(args[2], "a");
                        assert_eq!(args[3], "]");
                    }
                    _ => panic!("Expected Command node for test"),
                }

                // Second statement: first echo
                match &statements[1] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "echo");
                        assert_eq!(args[0], "first");
                    }
                    _ => panic!("Expected Command node for first echo"),
                }

                // Third statement: second echo
                match &statements[2] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "echo");
                        assert_eq!(args[0], "second");
                    }
                    _ => panic!("Expected Command node for second echo"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_bash_style_conditional_numeric_test_parsing() {
        // Test parsing of numeric comparison operators
        let input = r#"[ 5 -gt 3 ] && echo "greater""#;
        let result = parse_test(input);

        match result {
            Node::List {
                statements,
                operators,
            } => {
                assert_eq!(statements.len(), 2);
                assert_eq!(operators.len(), 1);
                assert_eq!(operators[0], "&&");

                // First statement should be the numeric test
                match &statements[0] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "[");
                        assert_eq!(args.len(), 4); // "5", "-gt", "3", "]"
                        assert_eq!(args[0], "5");
                        assert_eq!(args[1], "-gt");
                        assert_eq!(args[2], "3");
                        assert_eq!(args[3], "]");
                    }
                    _ => panic!("Expected Command node for numeric test"),
                }

                // Second statement should be the echo command
                match &statements[1] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "echo");
                        assert_eq!(args.len(), 1);
                        assert_eq!(args[0], "greater");
                    }
                    _ => panic!("Expected Command node for echo"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_logical_negation_parsing() {
        let input = "! echo test";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::Negation { command } => match command.as_ref() {
                        Node::Command { name, args, .. } => {
                            assert_eq!(name, "echo");
                            assert_eq!(args.len(), 1);
                            assert_eq!(args[0], "test");
                        }
                        _ => panic!("Expected Command node inside Negation"),
                    },
                    _ => panic!("Expected Negation node in statements"),
                }
            }
            _ => panic!("Expected List node, got: {result:?}"),
        }
    }

    #[test]
    fn test_negation_in_conditional() {
        let input = "if ! false; then echo success; fi";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::IfStatement {
                        condition,
                        consequence,
                        ..
                    } => {
                        match condition.as_ref() {
                            Node::Negation { command } => match command.as_ref() {
                                Node::Command { name, .. } => {
                                    assert_eq!(name, "false");
                                }
                                _ => panic!("Expected Command node inside Negation"),
                            },
                            _ => panic!("Expected Negation node in condition"),
                        }

                        match consequence.as_ref() {
                            Node::List { statements, .. } => {
                                assert_eq!(statements.len(), 1);
                                match &statements[0] {
                                    Node::Command { name, args, .. } => {
                                        assert_eq!(name, "echo");
                                        assert_eq!(args[0], "success");
                                    }
                                    _ => panic!("Expected Command node in then body statements"),
                                }
                            }
                            Node::Command { name, args, .. } => {
                                assert_eq!(name, "echo");
                                assert_eq!(args[0], "success");
                            }
                            _ => panic!("Expected Command or List node in then body"),
                        }
                    }
                    _ => panic!("Expected IfStatement node"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_command_builtin_parsing() {
        let input = "command echo test";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::Command { name, args, .. } => {
                        assert_eq!(name, "command");
                        assert_eq!(args.len(), 2);
                        assert_eq!(args[0], "echo");
                        assert_eq!(args[1], "test");
                    }
                    _ => panic!("Expected Command node in statements"),
                }
            }
            _ => panic!("Expected List node, got: {result:?}"),
        }
    }

    #[test]
    fn test_complete_builtin_parsing() {
        let input = "complete -F _test test";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::Complete { options, command } => {
                        assert_eq!(options.len(), 2);
                        assert_eq!(options[0], "-F");
                        assert_eq!(options[1], "_test");
                        assert_eq!(command, "test");
                    }
                    _ => panic!(
                        "Expected Complete node in statements, got: {:?}",
                        &statements[0]
                    ),
                }
            }
            _ => panic!("Expected List node, got: {result:?}"),
        }
    }

    #[test]
    fn test_history_expansion_parsing() {
        // Test !! parsing
        let input = "!!";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::HistoryExpansion { pattern } => {
                        assert_eq!(pattern, ""); // !! should have empty pattern
                    }
                    _ => panic!("Expected HistoryExpansion node in statements"),
                }
            }
            _ => panic!("Expected List node"),
        }

        // Test !command parsing
        let input = "!echo";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::HistoryExpansion { pattern } => {
                        assert_eq!(pattern, "echo");
                    }
                    _ => panic!("Expected HistoryExpansion node in statements"),
                }
            }
            _ => panic!("Expected List node"),
        }

        // Test !123 parsing
        let input = "!123";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::HistoryExpansion { pattern } => {
                        assert_eq!(pattern, "123");
                    }
                    _ => panic!("Expected HistoryExpansion node in statements"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_complex_negation_scenarios() {
        // Test double negation
        let input = "! ! true";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::Negation { command } => match command.as_ref() {
                        Node::Negation {
                            command: inner_command,
                        } => match inner_command.as_ref() {
                            Node::Command { name, .. } => {
                                assert_eq!(name, "true");
                            }
                            _ => panic!("Expected Command node in inner negation"),
                        },
                        _ => panic!("Expected Negation node inside outer negation"),
                    },
                    _ => panic!("Expected Negation node in statements"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_negation_with_command_builtin() {
        let input = "! command false";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::Negation { command } => match command.as_ref() {
                        Node::Command { name, args, .. } => {
                            assert_eq!(name, "command");
                            assert_eq!(args.len(), 1);
                            assert_eq!(args[0], "false");
                        }
                        _ => panic!("Expected Command node inside Negation"),
                    },
                    _ => panic!("Expected Negation node in statements"),
                }
            }
            _ => panic!("Expected List node"),
        }
    }

    #[test]
    fn test_negation_with_pipeline() {
        let input = "! echo test | grep test";
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::Negation { command } => match command.as_ref() {
                        Node::Pipeline { commands } => {
                            assert_eq!(commands.len(), 2);

                            match &commands[0] {
                                Node::Command { name, args, .. } => {
                                    assert_eq!(name, "echo");
                                    assert_eq!(args[0], "test");
                                }
                                _ => panic!("Expected Command node in pipeline"),
                            }

                            match &commands[1] {
                                Node::Command { name, args, .. } => {
                                    assert_eq!(name, "grep");
                                    assert_eq!(args[0], "test");
                                }
                                _ => panic!("Expected Command node in pipeline"),
                            }
                        }
                        _ => panic!("Expected Pipeline node inside Negation"),
                    },
                    _ => panic!(
                        "Expected Negation node in statements, got: {:?}",
                        &statements[0]
                    ),
                }
            }
            _ => panic!("Expected List node, got: {result:?}"),
        }
    }

    #[test]
    fn test_case_statement_parsing() {
        let input = r#"case hello in
            pattern1) echo "match1" ;;
            pattern2) echo "match2" ;;
        esac"#;
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::CaseStatement {
                        expression,
                        patterns,
                    } => {
                        // Check expression - it might be parsed as a command or string literal
                        match expression.as_ref() {
                            Node::StringLiteral(s) => assert_eq!(s, "hello"),
                            Node::Command { name, .. } => {
                                // If parsed as command, the name should be empty and we should have the variable
                                assert!(name.is_empty() || name == "hello");
                            }
                            _ => panic!(
                                "Expected StringLiteral or Command for case expression, got: {expression:?}"
                            ),
                        }

                        // Check patterns - should have 2 simple patterns
                        assert_eq!(patterns.len(), 2);

                        // First pattern
                        assert_eq!(patterns[0].patterns, vec!["pattern1"]);

                        // Second pattern
                        assert_eq!(patterns[1].patterns, vec!["pattern2"]);
                    }
                    _ => panic!("Expected CaseStatement, got: {:?}", &statements[0]),
                }
            }
            _ => panic!("Expected List node, got: {result:?}"),
        }
    }

    #[test]
    fn test_simple_case_statement() {
        let input = r#"case hello in
            hello) echo "found" ;;
        esac"#;
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::CaseStatement {
                        expression,
                        patterns,
                    } => {
                        match expression.as_ref() {
                            Node::StringLiteral(s) => assert_eq!(s, "hello"),
                            _ => panic!("Expected StringLiteral for case expression"),
                        }

                        assert_eq!(patterns.len(), 1);
                        assert_eq!(patterns[0].patterns, vec!["hello"]);
                    }
                    _ => panic!("Expected CaseStatement, got: {:?}", &statements[0]),
                }
            }
            _ => panic!("Expected List node, got: {result:?}"),
        }
    }

    #[test]
    fn test_case_statement_with_variables() {
        let input = r#"case "$USER" in
            root) echo "admin" ;;
            *) echo "user" ;;
        esac"#;
        let result = parse_test(input);

        match result {
            Node::List { statements, .. } => {
                assert_eq!(statements.len(), 1);
                match &statements[0] {
                    Node::CaseStatement {
                        expression,
                        patterns,
                    } => {
                        match expression.as_ref() {
                            Node::StringLiteral(s) => assert_eq!(s, "$USER"),
                            _ => panic!("Expected StringLiteral for case expression"),
                        }

                        assert_eq!(patterns.len(), 2);
                        assert_eq!(patterns[0].patterns, vec!["root"]);
                        assert_eq!(patterns[1].patterns, vec!["*"]);
                    }
                    _ => panic!("Expected CaseStatement, got: {:?}", &statements[0]),
                }
            }
            _ => panic!("Expected List node, got: {result:?}"),
        }
    }
}
