from typing import List, Dict, Any
from .base_tests import BaseTestGenerator


class IdentifierTestGenerator(BaseTestGenerator):
    """Generate test cases for identifiers and identifier literals."""
    
    # Reserved words that might be operators or keywords
    RESERVED_WORDS = [
        'if', 'while', 'for', 'match', 'break', 'continue',
        'fn', 'struct', 'union', 'enum', 'trait', 'impl', 'inher',
        'dup', 'drop', 'swap', 'over', 'rot', 'pick', 'roll', 'depth',
    ]
    
    def generate_basic_identifier_tests(self):
        """Generate basic identifier tests."""
        # Simple identifiers
        self.make_success_test("Identifier Simple Lowercase", "hello", 
                              "identifier", "hello")
        self.make_success_test("Identifier Simple Uppercase", "HELLO",
                              "identifier", "HELLO")
        self.make_success_test("Identifier Mixed Case", "HelloWorld",
                              "identifier", "HelloWorld")
        self.make_success_test("Identifier Single Letter", "x",
                              "identifier", "x")
        self.make_success_test("Identifier Single Letter Upper", "X",
                              "identifier", "X")
        
        # Identifiers with numbers
        self.make_success_test("Identifier With Numbers", "var123",
                              "identifier", "var123")
        self.make_success_test("Identifier Numbers End", "myVar2",
                              "identifier", "myVar2")
        self.make_success_test("Identifier Mixed Numbers", "a1b2c3",
                              "identifier", "a1b2c3")
        
        # Identifiers with underscores
        self.make_success_test("Identifier With Underscore", "hello_world",
                              "identifier", "hello_world")
        self.make_success_test("Identifier Leading Underscore", "_private",
                              "identifier", "_private")
        self.make_success_test("Identifier Multiple Underscores", "my_long_var_name",
                              "identifier", "my_long_var_name")
        self.make_success_test("Identifier Double Underscore", "my__var",
                              "identifier", "my__var")
        self.make_success_test("Identifier Trailing Underscore", "var_",
                              "identifier", "var_")
        self.make_success_test("Identifier Only Underscores", "___",
                              "identifier", "___")
        
        # Snake case
        self.make_success_test("Identifier Snake Case", "my_variable_name",
                              "identifier", "my_variable_name")
        
        # Camel case
        self.make_success_test("Identifier Camel Case", "myVariableName",
                              "identifier", "myVariableName")
        
        # Pascal case
        self.make_success_test("Identifier Pascal Case", "MyClassName",
                              "identifier", "MyClassName")
        
        # All caps with underscores
        self.make_success_test("Identifier All Caps", "MY_CONSTANT",
                              "identifier", "MY_CONSTANT")
        
        # Others
        self.make_success_test("Identifier With Dash", "my-var",
                              "identifier", "my-var")
    
    def generate_identifier_literal_tests(self):
        """Generate identifier literal tests (with :: prefix)."""
        # Simple identifier literals
        self.make_success_test("Identifier Literal Simple", "::hello",
                              "identifier_literal", "hello")
        self.make_success_test("Identifier Literal Uppercase", "::Point",
                              "identifier_literal", "Point")
        self.make_success_test("Identifier Literal Snake Case", "::my_var",
                              "identifier_literal", "my_var")
        
        # Type names
        self.make_success_test("Identifier Literal Type i64", "::i64",
                              "identifier_literal", "i64")
        self.make_success_test("Identifier Literal Type String", "::String",
                              "identifier_literal", "String")
        self.make_success_test("Identifier Literal Type Point", "::Point",
                              "identifier_literal", "Point")
        
        # Trait names
        self.make_success_test("Identifier Literal Trait Addable", "::Addable",
                              "identifier_literal", "Addable")
        self.make_success_test("Identifier Literal Trait Drawable", "::Drawable",
                              "identifier_literal", "Drawable")
        
        # Field names
        self.make_success_test("Identifier Literal Field x", "::x",
                              "identifier_literal", "x")
        self.make_success_test("Identifier Literal Field width", "::width",
                              "identifier_literal", "width")
        
        # With underscores
        self.make_success_test("Identifier Literal With Underscore", "::_private",
                              "identifier_literal", "_private")
        self.make_success_test("Identifier Literal Multiple Underscores", "::my_long_name",
                              "identifier_literal", "my_long_name")
        
        # With numbers
        self.make_success_test("Identifier Literal With Numbers", "::var123",
                              "identifier_literal", "var123")
    
    def generate_whitespace_tests(self):
        """Generate tests with whitespace around identifiers."""
        # Regular identifiers with whitespace
        self.make_success_test("Identifier Leading Whitespace", "  hello",
                              "identifier", "hello")
        self.make_success_test("Identifier Trailing Whitespace", "hello  ",
                              "identifier", "hello")
        self.make_success_test("Identifier Both Whitespace", "  hello  ",
                              "identifier", "hello")
        self.make_success_test("Identifier Tab Before", "\\thello",
                              "identifier", "hello")
        
        # Identifier literals with whitespace
        self.make_success_test("Identifier Literal Leading Whitespace", "  ::hello",
                              "identifier_literal", "hello")
        self.make_success_test("Identifier Literal Trailing Whitespace", "::hello  ",
                              "identifier_literal", "hello")
        self.make_success_test("Identifier Literal Both Whitespace", "  ::hello  ",
                              "identifier_literal", "hello")
    
    def generate_long_identifier_tests(self):
        """Generate tests for longer identifiers."""
        # Moderately long
        self.make_success_test("Identifier Moderate Length",
                              "thisIsAReasonablyLongVariableName",
                              "identifier", "thisIsAReasonablyLongVariableName")
        
        # Very long
        long_name = "this_is_a_very_long_identifier_name_that_someone_might_use_for_some_reason"
        self.make_success_test("Identifier Very Long", long_name,
                              "identifier", long_name)
        
        # Long with numbers
        long_with_nums = "variable_with_many_numbers_123_456_789_000"
        self.make_success_test("Identifier Long With Numbers", long_with_nums,
                              "identifier", long_with_nums)
    
    def generate_error_tests(self):
        """Generate error test cases for identifiers."""
        # Starting with number
        self.make_error_test("Identifier Starting With Number",
                           "123abc",
                           "Invalid decimal literal: unexpected 'a' in decimal integer.")
        
        # Invalid characters
        self.make_success_test("Identifier With Octothorpe", "my#var",
                           "identifier", "my")
        
        # self.make_error_test("Identifier With Space",
        #                    "my var",
        #                    "Invalid identifier: whitespace not allowed in identifiers.")
        
        self.make_error_test("Identifier With Colon",
                           "my:var",
                           "Invalid identifier: ':' is not allowed in identifiers.")
        
        # Note: :: is allowed only as prefix for identifier literals
        self.make_error_test("Identifier Double Colon Inside",
                           "my::var",
                           "Invalid identifier: ':' is not allowed in identifiers.")
        
        # Special characters
        # self.make_error_test("Identifier With At",
        #                    "@variable",
        #                    "Invalid identifier: '@' is not allowed in identifiers.")
        
        # self.make_error_test("Identifier With Dollar",
        #                    "$variable",
        #                    "Invalid identifier: '$' is not allowed in identifiers.")
        
        # self.make_error_test("Identifier With Percent",
        #                    "%variable",
        #                    "Invalid identifier: '%' is not allowed in identifiers.")
        
        # Brackets not allowed
        # self.make_error_test("Identifier With Brackets",
        #                    "my[var]",
        #                    "Invalid identifier: brackets not allowed in identifiers.")
        
        # self.make_error_test("Identifier With Braces",
        #                    "my{var}",
        #                    "Invalid identifier: braces not allowed in identifiers.")
        
        # self.make_error_test("Identifier With Parens",
        #                    "my(var)",
        #                    "Invalid identifier: parentheses not allowed in identifiers.")
        
        # Quotes not allowed
        # self.make_error_test("Identifier With Single Quote",
        #                    "my'var",
        #                    "Invalid identifier: quotes not allowed in identifiers.")
        
        # self.make_error_test("Identifier With Double Quote",
        #                    'my"var',
        #                    "Invalid identifier: quotes not allowed in identifiers.")
        
        # Only numbers (not valid identifier)
        self.make_success_test("Identifier Only Numbers", "123", "i64", 123)
        
        # Empty identifier literal
        self.make_error_test("Identifier Literal Empty",
                           "::",
                           "Invalid identifier literal: empty identifier after '::'.")
    
    def generate_case_sensitivity_tests(self):
        """Generate tests showing case sensitivity."""
        # These should all be different identifiers
        self.make_success_test("Identifier Case Lower", "variable",
                              "identifier", "variable")
        self.make_success_test("Identifier Case Upper", "VARIABLE",
                              "identifier", "VARIABLE")
        self.make_success_test("Identifier Case Mixed", "Variable",
                              "identifier", "Variable")
        self.make_success_test("Identifier Case Camel", "variableName",
                              "identifier", "variableName")
        self.make_success_test("Identifier Case Pascal", "VariableName",
                              "identifier", "VariableName")
    
    def generate_reserved_word_tests(self):
        """Generate tests for words that might be reserved."""
        # Note: In the spec, these are treated as identifiers/operators
        # This tests that they're recognized correctly
        for word in self.RESERVED_WORDS:
            self.make_success_test(f"Identifier Reserved Word {word}",
                                  word, "identifier", word)
    
    def generate_all_tests(self) -> List[Dict[str, Any]]:
        """Generate all identifier test cases."""
        # Basic identifiers
        self.generate_basic_identifier_tests()
        
        # Identifier literals
        self.generate_identifier_literal_tests()
        
        # Whitespace handling
        self.generate_whitespace_tests()
        
        # Long identifiers
        self.generate_long_identifier_tests()
        
        # Error cases
        self.generate_error_tests()
        
        # Case sensitivity
        self.generate_case_sensitivity_tests()
        
        # Reserved words
        self.generate_reserved_word_tests()
        
        return self.get_tests()


class BooleanTestGenerator(BaseTestGenerator):
    """Generate test cases for boolean literals."""
    
    def generate_basic_tests(self):
        """Generate basic boolean literal tests."""
        # True
        self.make_success_test("Bool True", "true", "bool", True)
        
        # False
        self.make_success_test("Bool False", "false", "bool", False)
    
    def generate_whitespace_tests(self):
        """Generate tests with whitespace around booleans."""
        # True with whitespace
        self.make_success_test("Bool True Leading Whitespace", "  true",
                              "bool", True)
        self.make_success_test("Bool True Trailing Whitespace", "true  ",
                              "bool", True)
        self.make_success_test("Bool True Both Whitespace", "  true  ",
                              "bool", True)
        self.make_success_test("Bool True Tab Before", "\\ttrue",
                              "bool", True)
        
        # False with whitespace
        self.make_success_test("Bool False Leading Whitespace", "  false",
                              "bool", False)
        self.make_success_test("Bool False Trailing Whitespace", "false  ",
                              "bool", False)
        self.make_success_test("Bool False Both Whitespace", "  false  ",
                              "bool", False)
        self.make_success_test("Bool False Tab Before", "\\tfalse",
                              "bool", False)
    
    def generate_error_tests(self):
        """Generate error test cases for booleans."""
        # Capitalized (case sensitive)
        self.make_success_test("Bool True Capitalized", "True",
                           "identifier", "True")
        
        self.make_success_test("Bool False Capitalized", "False",
                           "identifier", "False")
        
        # All caps
        self.make_success_test("Bool True All Caps", "TRUE",
                           "identifier", "TRUE")
        
        self.make_success_test("Bool False All Caps", "FALSE",
                           "identifier", "FALSE")
        
        # Mixed case
        self.make_success_test("Bool True Mixed Case", "tRuE",
                           "identifier", "tRuE")
        
        self.make_success_test("Bool False Mixed Case", "fAlSe",
                           "identifier", "fAlSe")
        
        # Numeric representations
        self.make_success_test("Bool Numeric 1", "1", "i64", 1)
        
        self.make_success_test("Bool Numeric 0", "0", "i64", 0)
        
        # String representations
        if self.ENABLE_STRINGS:
            self.make_success_test("Bool String True", '"true"',
                            "string", "true")
            
            self.make_success_test("Bool String False", '"false"',
                            "string", "false")
        
        # Other languages
        self.make_success_test("Bool Yes", "yes",
                           "identifier", "yes")
        
        self.make_success_test("Bool No", "no",
                           "identifier", "no")
        
        # Typos
        self.make_success_test("Bool Typo Ture", "ture",
                           "identifier", "ture")
        
        self.make_success_test("Bool Typo Flase", "flase",
                           "identifier", "flase")
    
    def generate_multiple_bool_tests(self):
        """Generate tests with multiple boolean values."""
        # Multiple values on stack
        self.make_multi_value_test("Bool Multiple True False",
                                   "true false",
                                   [("bool", True), ("bool", False)])
        
        self.make_multi_value_test("Bool Multiple Same",
                                   "true true",
                                   [("bool", True), ("bool", True)])
        
        self.make_multi_value_test("Bool Three Values",
                                   "true false true",
                                   [("bool", True), ("bool", False), ("bool", True)])
    
    def generate_all_tests(self) -> List[Dict[str, Any]]:
        """Generate all boolean test cases."""
        # Basic tests
        self.generate_basic_tests()
        
        # Whitespace handling
        self.generate_whitespace_tests()
        
        # Error cases
        self.generate_error_tests()
        
        # Multiple booleans
        self.generate_multiple_bool_tests()
        
        return self.get_tests()
