use super::Parser;
use crate::error::{Result, SoppoError};
use crate::syntax::ast::{
    ConstDecl, Decl, EnumVariant, Expr, ExprKind, Field, File, FuncDecl, Generic, Import,
    InterfaceMethod, Param, TypeDecl, TypeKind,
};
use crate::syntax::lexer::Token;
use crate::syntax::source::Span;

impl Parser {
    /// Parse function parameter
    fn parse_param(&mut self) -> Result<Param> {
        // Go syntax: name Type (no colon)
        let (name, name_span) = match self.advance() {
            Some((Token::Ident(name), span)) => (name, span),
            Some((tok, span)) => {
                return Err(SoppoError::Parse {
                    message: format!("Expected parameter name, found {:?}", tok),
                    span,
                });
            }
            None => {
                return Err(SoppoError::Parse {
                    message: "Expected parameter name".to_string(),
                    span: Span::dummy(),
                });
            }
        };

        self.validate_identifier(&name, &name_span)?;

        let ty = self.parse_type()?;

        Ok(Param {
            name,
            ty,
            span: name_span,
        })
    }

    /// Parse function parameter list with support for grouped parameters: (a, b int, c string)
    fn parse_param_list(&mut self) -> Result<Vec<Param>> {
        let mut params = Vec::new();

        if matches!(self.peek(), Some(Token::RParen)) {
            return Ok(params);
        }

        let mut pending_names: Vec<(String, Span)> = Vec::new();

        loop {
            // Parse name
            let (name, name_span) = match self.advance() {
                Some((Token::Ident(name), span)) => (name, span),
                Some((tok, span)) => {
                    return Err(SoppoError::Parse {
                        message: format!("Expected parameter name, found {:?}", tok),
                        span,
                    });
                }
                None => {
                    return Err(SoppoError::Parse {
                        message: "Expected parameter name".to_string(),
                        span: Span::dummy(),
                    });
                }
            };

            self.validate_identifier(&name, &name_span)?;
            pending_names.push((name, name_span));

            if self.consume(&Token::Comma) {
                // Could be more names in the group, or end of a param group
                // Continue to parse next name
                continue;
            }

            // No comma - parse the type for all pending names
            let ty = self.parse_type()?;

            // Assign type to all pending names
            for (name, span) in pending_names.drain(..) {
                params.push(Param {
                    name,
                    ty: ty.clone(),
                    span,
                });
            }

            // Check if there's another parameter group
            if self.consume(&Token::Comma) {
                continue;
            }

            break;
        }

        Ok(params)
    }

    /// Parse generic parameters: [T any, E comparable]
    fn parse_generics(&mut self) -> Result<Vec<Generic>> {
        if !self.consume(&Token::LBracket) {
            return Ok(Vec::new());
        }

        let mut generics = Vec::new();

        if !matches!(self.peek(), Some(Token::RBracket)) {
            loop {
                let (name, span) = match self.advance() {
                    Some((Token::Ident(name), span)) => (name, span),
                    Some((tok, span)) => {
                        return Err(SoppoError::Parse {
                            message: format!("Expected generic parameter name, found {:?}", tok),
                            span,
                        });
                    }
                    None => {
                        return Err(SoppoError::Parse {
                            message: "Expected generic parameter name".to_string(),
                            span: Span::dummy(),
                        });
                    }
                };

                // Parse constraint (required in Go): T any, E comparable, etc.
                let constraint = match self.advance() {
                    Some((Token::Ident(constraint), _)) => constraint,
                    Some((tok, span)) => {
                        return Err(SoppoError::Parse {
                            message: format!(
                                "Expected type constraint (e.g., 'any', 'comparable'), found {:?}",
                                tok
                            ),
                            span,
                        });
                    }
                    None => {
                        return Err(SoppoError::Parse {
                            message: "Expected type constraint".to_string(),
                            span: Span::dummy(),
                        });
                    }
                };

                generics.push(Generic {
                    name,
                    constraint,
                    span,
                });

                if !self.consume(&Token::Comma) {
                    break;
                }
            }
        }

        self.expect(Token::RBracket)?;
        Ok(generics)
    }

    /// Parse function declaration
    pub fn parse_func_decl(&mut self) -> Result<FuncDecl> {
        let start_span = self.expect(Token::Func)?;

        // Check for receiver: func (r: Type) name() or func name()
        let receiver = if self.consume(&Token::LParen) {
            let param = self.parse_param()?;
            self.expect(Token::RParen)?;
            Some(param)
        } else {
            None
        };

        let (name, name_span) = match self.advance() {
            Some((Token::Ident(name), span)) => (name, span),
            Some((tok, span)) => {
                return Err(SoppoError::Parse {
                    message: format!("Expected function name, found {:?}", tok),
                    span,
                });
            }
            None => {
                return Err(SoppoError::Parse {
                    message: "Expected function name".to_string(),
                    span: Span::dummy(),
                });
            }
        };

        self.validate_identifier(&name, &name_span)?;

        // Parse optional generics [T any, U any]
        let generics = self.parse_generics()?;

        // Parse parameters (supports grouped params: a, b int)
        self.expect(Token::LParen)?;
        let params = self.parse_param_list()?;
        self.expect(Token::RParen)?;

        // Parse optional return type(s)
        // Go-style: single type or (type1, type2, ...)
        let return_types = if matches!(self.peek(), Some(Token::LBrace)) {
            // No return type
            vec![]
        } else if self.consume(&Token::LParen) {
            // Multi-value return: (int, string, error)
            let mut types = vec![];
            if !matches!(self.peek(), Some(Token::RParen)) {
                loop {
                    types.push(self.parse_type()?);
                    if !self.consume(&Token::Comma) {
                        break;
                    }
                }
            }
            self.expect(Token::RParen)?;
            types
        } else {
            // Single return type
            vec![self.parse_type()?]
        };

        // Parse body
        let body = self.parse_block()?;

        Ok(FuncDecl {
            receiver,
            name,
            generics,
            params,
            return_types,
            body: body.clone(),
            span: Span::with_bytes(
                start_span.start,
                body.span.end,
                self.file,
                start_span.byte_start,
                body.span.byte_end,
            ),
        })
    }

    /// Parse type declaration (enum or struct)
    pub(super) fn parse_type_decl(&mut self) -> Result<TypeDecl> {
        let start_span = self.expect(Token::Type)?;

        let (name, name_span) = match self.advance() {
            Some((Token::Ident(name), span)) => (name, span),
            Some((tok, span)) => {
                return Err(SoppoError::Parse {
                    message: format!("Expected type name, found {:?}", tok),
                    span,
                });
            }
            None => {
                return Err(SoppoError::Parse {
                    message: "Expected type name".to_string(),
                    span: Span::dummy(),
                });
            }
        };

        self.validate_identifier(&name, &name_span)?;

        // Parse optional generics [T any, U any]
        let generics = self.parse_generics()?;

        // Check for 'enum', 'struct', or type alias
        let (kind, end_span) = if self.consume(&Token::Enum) {
            // Parse enum
            self.expect(Token::LBrace)?;
            // Skip terminators after opening brace
            self.skip_terminators();

            let mut variants = Vec::new();

            while !matches!(self.peek(), Some(Token::RBrace) | None) {
                let variant = self.parse_enum_variant()?;
                variants.push(variant);

                // Terminators as separator (like Go struct fields)
                self.skip_terminators();
            }

            let end_span = self.expect(Token::RBrace)?;
            (TypeKind::Enum { variants }, end_span)
        } else if self.consume(&Token::Struct) {
            // Parse struct
            self.expect(Token::LBrace)?;
            // Skip terminators after opening brace
            self.skip_terminators();

            let mut fields = Vec::new();

            while !matches!(self.peek(), Some(Token::RBrace) | None) {
                let parsed_fields = self.parse_fields()?;
                fields.extend(parsed_fields);

                // Terminators as separator (like Go struct fields)
                self.skip_terminators();
            }

            let end_span = self.expect(Token::RBrace)?;
            (TypeKind::Struct { fields }, end_span)
        } else if self.consume(&Token::Interface) {
            // Parse interface
            self.expect(Token::LBrace)?;
            // Skip terminators after opening brace
            self.skip_terminators();

            let mut methods = Vec::new();

            while !matches!(self.peek(), Some(Token::RBrace) | None) {
                let method = self.parse_interface_method()?;
                methods.push(method);

                // Terminators as separator
                self.skip_terminators();
            }

            let end_span = self.expect(Token::RBrace)?;
            (TypeKind::Interface { methods }, end_span)
        } else if self.consume(&Token::Assign) {
            // Type alias: type Foo = Bar (Foo is exactly Bar)
            let target = self.parse_type()?;
            let end_span = target.span;
            (TypeKind::Alias { target }, end_span)
        } else {
            // Type definition: type Foo Bar (Foo is a new distinct type based on Bar)
            let target = self.parse_type()?;
            let end_span = target.span;
            (TypeKind::Definition { target }, end_span)
        };

        Ok(TypeDecl {
            name,
            generics,
            kind,
            span: Span::with_bytes(
                start_span.start,
                end_span.end,
                self.file,
                start_span.byte_start,
                end_span.byte_end,
            ),
        })
    }

    /// Parse enum variant
    fn parse_enum_variant(&mut self) -> Result<EnumVariant> {
        let (name, name_span) = match self.advance() {
            Some((Token::Ident(name), span)) => (name, span),
            Some((tok, span)) => {
                return Err(SoppoError::Parse {
                    message: format!("Expected variant name, found {:?}", tok),
                    span,
                });
            }
            None => {
                return Err(SoppoError::Parse {
                    message: "Expected variant name".to_string(),
                    span: Span::dummy(),
                });
            }
        };

        // Check for data: Single Type or Struct { fields }
        // Optional `struct` keyword before `{`
        let has_struct_keyword = self.consume(&Token::Struct);
        if has_struct_keyword || self.consume(&Token::LBrace) {
            // If we consumed `struct`, now consume the `{`
            if has_struct_keyword {
                self.expect(Token::LBrace)?;
            }
            // Skip terminators after opening brace
            self.skip_terminators();

            // Struct variant
            let mut fields = Vec::new();

            while !matches!(self.peek(), Some(Token::RBrace) | None) {
                let parsed_fields = self.parse_fields()?;
                fields.extend(parsed_fields);

                // Terminators as separator (like Go struct fields)
                self.skip_terminators();
            }

            let end_span = self.expect(Token::RBrace)?;

            Ok(EnumVariant::Struct {
                name,
                fields,
                span: Span::with_bytes(
                    name_span.start,
                    end_span.end,
                    self.file,
                    name_span.byte_start,
                    end_span.byte_end,
                ),
            })
        } else if self.is_terminator() {
            // Terminator after variant name - unit variant (like Go struct embedded field on its own line)
            Ok(EnumVariant::Unit {
                name,
                span: name_span,
            })
        } else if matches!(
            self.peek(),
            Some(Token::Ident(_)) | Some(Token::LBracket) | Some(Token::Star)
        ) {
            // Array or pointer type follows
            let ty = self.parse_type()?;

            Ok(EnumVariant::Single {
                name,
                ty,
                span: name_span,
            })
        } else {
            // Unit variant
            Ok(EnumVariant::Unit {
                name,
                span: name_span,
            })
        }
    }

    /// Parse struct fields (supports grouped names like `X, Y int`)
    /// Returns a Vec because `X, Y int` produces multiple Field entries
    pub fn parse_fields(&mut self) -> Result<Vec<Field>> {
        // Collect all field names (comma-separated)
        let mut names: Vec<(String, Span)> = Vec::new();

        // Parse first name
        let (first_name, first_span) = match self.advance() {
            Some((Token::Ident(name), span)) => (name, span),
            Some((tok, span)) => {
                return Err(SoppoError::Parse {
                    message: format!("Expected field name, found {:?}", tok),
                    span,
                });
            }
            None => {
                return Err(SoppoError::Parse {
                    message: "Expected field name".to_string(),
                    span: Span::dummy(),
                });
            }
        };
        names.push((first_name, first_span));

        // Parse additional comma-separated names
        while self.consume(&Token::Comma) {
            let (name, span) = match self.advance() {
                Some((Token::Ident(name), span)) => (name, span),
                Some((tok, span)) => {
                    return Err(SoppoError::Parse {
                        message: format!("Expected field name after comma, found {:?}", tok),
                        span,
                    });
                }
                None => {
                    return Err(SoppoError::Parse {
                        message: "Expected field name after comma".to_string(),
                        span: Span::dummy(),
                    });
                }
            };
            names.push((name, span));
        }

        // Parse the type (shared by all names)
        let ty = self.parse_type()?;

        // Parse optional struct tag (backtick string) - only applies to last field in Go
        // but we'll apply it to all for simplicity
        let tag = match self.peek() {
            Some(Token::RawString(_)) => {
                if let Some((Token::RawString(s), _)) = self.advance() {
                    Some(s)
                } else {
                    None
                }
            }
            _ => None,
        };

        // Create a Field for each name
        let fields = names
            .into_iter()
            .map(|(name, span)| Field {
                name,
                ty: ty.clone(),
                tag: tag.clone(),
                span,
            })
            .collect();

        Ok(fields)
    }

    /// Parse interface method signature: MethodName(params) returns
    fn parse_interface_method(&mut self) -> Result<InterfaceMethod> {
        let (name, name_span) = match self.advance() {
            Some((Token::Ident(name), span)) => (name, span),
            Some((tok, span)) => {
                return Err(SoppoError::Parse {
                    message: format!("Expected method name, found {:?}", tok),
                    span,
                });
            }
            None => {
                return Err(SoppoError::Parse {
                    message: "Expected method name".to_string(),
                    span: Span::dummy(),
                });
            }
        };

        // Parse parameters (supports grouped params: a, b int)
        self.expect(Token::LParen)?;
        let params = self.parse_param_list()?;
        let end_span = self.expect(Token::RParen)?;

        // Parse optional return type(s)
        let (returns, final_span) = if matches!(
            self.peek(),
            Some(Token::Newline) | Some(Token::RBrace) | None
        ) {
            // No return type
            (vec![], end_span)
        } else if self.consume(&Token::LParen) {
            // Multi-value return: (int, string, error)
            let mut types = vec![];
            if !matches!(self.peek(), Some(Token::RParen)) {
                loop {
                    types.push(self.parse_type()?);
                    if !self.consume(&Token::Comma) {
                        break;
                    }
                }
            }
            let rparen_span = self.expect(Token::RParen)?;
            (types, rparen_span)
        } else {
            // Single return type
            let ty = self.parse_type()?;
            let ty_span = ty.span;
            (vec![ty], ty_span)
        };

        Ok(InterfaceMethod {
            name,
            params,
            returns,
            span: Span::with_bytes(
                name_span.start,
                final_span.end,
                self.file,
                name_span.byte_start,
                final_span.byte_end,
            ),
        })
    }

    /// Parse top-level declaration
    pub fn parse_decl(&mut self) -> Result<Decl> {
        match self.peek() {
            Some(Token::Const) => Ok(Decl::Const(self.parse_const_decl()?)),
            Some(Token::Func) => Ok(Decl::Func(self.parse_func_decl()?)),
            Some(Token::Type) => Ok(Decl::Type(self.parse_type_decl()?)),
            Some(tok) => Err(SoppoError::Parse {
                message: format!("Expected declaration, found {:?}", tok),
                span: self.peek_span(),
            }),
            None => Err(SoppoError::Parse {
                message: "Expected declaration".to_string(),
                span: Span::dummy(),
            }),
        }
    }

    /// Parse a const declaration: const NAME = VALUE or const NAME TYPE = VALUE
    fn parse_const_decl(&mut self) -> Result<ConstDecl> {
        let start = self.expect(Token::Const)?;

        let (name, name_span) = match self.advance() {
            Some((Token::Ident(name), span)) => (name, span),
            Some((tok, span)) => {
                return Err(SoppoError::Parse {
                    message: format!("Expected identifier, found {:?}", tok),
                    span,
                });
            }
            None => {
                return Err(SoppoError::Parse {
                    message: "Expected identifier".to_string(),
                    span: self.peek_span(),
                });
            }
        };

        self.validate_identifier(&name, &name_span)?;

        // Check if next token is = (type inference) or a type name
        let ty = if self.consume(&Token::Assign) {
            // const NAME = VALUE (type inference)
            None
        } else if matches!(
            self.peek(),
            Some(Token::Ident(_)) | Some(Token::LBracket) | Some(Token::Star)
        ) {
            // const NAME TYPE = VALUE (explicit type)
            let ty = self.parse_type()?;
            self.expect(Token::Assign)?;
            Some(ty)
        } else {
            return Err(SoppoError::Parse {
                message: "Expected type or '=' in const declaration".to_string(),
                span: name_span,
            });
        };

        let value = self.parse_expr()?;

        Ok(ConstDecl {
            name,
            ty,
            value,
            span: start,
        })
    }

    /// Parse a const declaration after the 'const' keyword has been consumed
    fn parse_const_after_keyword(&mut self) -> Result<ConstDecl> {
        let start = self.peek_span();

        let (name, name_span) = match self.advance() {
            Some((Token::Ident(name), span)) => (name, span),
            Some((tok, span)) => {
                return Err(SoppoError::Parse {
                    message: format!("Expected identifier, found {:?}", tok),
                    span,
                });
            }
            None => {
                return Err(SoppoError::Parse {
                    message: "Expected identifier".to_string(),
                    span: self.peek_span(),
                });
            }
        };

        self.validate_identifier(&name, &name_span)?;

        // Check if next token is = (type inference) or a type name
        let ty = if self.consume(&Token::Assign) {
            None
        } else if matches!(
            self.peek(),
            Some(Token::Ident(_)) | Some(Token::LBracket) | Some(Token::Star)
        ) {
            let ty = self.parse_type()?;
            self.expect(Token::Assign)?;
            Some(ty)
        } else {
            return Err(SoppoError::Parse {
                message: "Expected type or '=' in const declaration".to_string(),
                span: name_span,
            });
        };

        let value = self.parse_expr()?;

        Ok(ConstDecl {
            name,
            ty,
            value,
            span: start,
        })
    }

    /// Parse a const declaration inside a grouped const block
    /// Supports: NAME = VALUE, NAME TYPE = VALUE, NAME (implicit iota continuation)
    fn parse_const_in_group(&mut self) -> Result<ConstDecl> {
        let start = self.peek_span();

        let (name, name_span) = match self.advance() {
            Some((Token::Ident(name), span)) => (name, span),
            Some((tok, span)) => {
                return Err(SoppoError::Parse {
                    message: format!("Expected identifier, found {:?}", tok),
                    span,
                });
            }
            None => {
                return Err(SoppoError::Parse {
                    message: "Expected identifier".to_string(),
                    span: self.peek_span(),
                });
            }
        };

        self.validate_identifier(&name, &name_span)?;

        // In grouped const, we might have:
        // 1. NAME = VALUE
        // 2. NAME TYPE = VALUE
        // 3. NAME (implicit, uses previous iota value - for Go compatibility)
        let (ty, value) = if self.consume(&Token::Assign) {
            // NAME = VALUE
            let value = self.parse_expr()?;
            (None, value)
        } else if matches!(
            self.peek(),
            Some(Token::Ident(_)) | Some(Token::LBracket) | Some(Token::Star)
        ) {
            // Could be NAME TYPE = VALUE or NAME (implicit)
            // Need to check if after type there's an =
            let ty = self.parse_type()?;
            if self.consume(&Token::Assign) {
                let value = self.parse_expr()?;
                (Some(ty), value)
            } else {
                // Implicit iota continuation - generate iota as value
                // For now, we require explicit values
                return Err(SoppoError::Parse {
                    message: "Expected '=' after type in const declaration".to_string(),
                    span: name_span,
                });
            }
        } else if matches!(
            self.peek(),
            Some(&Token::Newline) | Some(&Token::RParen) | None
        ) {
            // Implicit iota continuation (NAME on its own line)
            // Generate an iota expression - Go will handle the incrementing
            let iota_expr = Expr {
                kind: ExprKind::Ident("iota".to_string()),
                span: name_span,
            };
            (None, iota_expr)
        } else {
            return Err(SoppoError::Parse {
                message: "Expected type, '=', or newline in const declaration".to_string(),
                span: name_span,
            });
        };

        Ok(ConstDecl {
            name,
            ty,
            value,
            span: start,
        })
    }

    /// Parse a single import: "path" or alias "path"
    fn parse_single_import(&mut self) -> Result<Import> {
        match self.advance() {
            Some((Token::String(path), span)) => {
                // Simple import: "path"
                Ok(Import {
                    alias: None,
                    path,
                    span,
                })
            }
            Some((Token::Ident(alias), start_span)) => {
                // Aliased import: alias "path"
                match self.advance() {
                    Some((Token::String(path), _end_span)) => Ok(Import {
                        alias: Some(alias),
                        path,
                        span: start_span,
                    }),
                    Some((tok, span)) => Err(SoppoError::Parse {
                        message: format!(
                            "Expected import path string after alias, found {:?}",
                            tok
                        ),
                        span,
                    }),
                    None => Err(SoppoError::Parse {
                        message: "Expected import path string after alias".to_string(),
                        span: start_span,
                    }),
                }
            }
            Some((tok, span)) => Err(SoppoError::Parse {
                message: format!("Expected import path or alias, found {:?}", tok),
                span,
            }),
            None => Err(SoppoError::Parse {
                message: "Expected import path".to_string(),
                span: Span::dummy(),
            }),
        }
    }

    /// Parse a complete file
    pub fn parse_file(&mut self) -> Result<File> {
        // Skip leading whitespace/newlines
        self.skip_terminators();

        // Parse package declaration
        let package = if self.consume(&Token::Package) {
            let name = match self.advance() {
                Some((Token::Ident(name), _)) => name,
                Some((tok, span)) => {
                    return Err(SoppoError::Parse {
                        message: format!("Expected package name, found {:?}", tok),
                        span,
                    });
                }
                None => {
                    return Err(SoppoError::Parse {
                        message: "Expected package name".to_string(),
                        span: Span::dummy(),
                    });
                }
            };
            // Skip terminators after package declaration
            self.skip_terminators();
            name
        } else {
            "main".to_string()
        };

        // Parse imports
        let mut imports = Vec::new();
        while self.consume(&Token::Import) {
            if self.consume(&Token::LParen) {
                // Grouped imports: import ( ... )
                self.skip_terminators();
                while self.peek() != Some(&Token::RParen) {
                    imports.push(self.parse_single_import()?);
                    self.skip_terminators();
                }
                self.expect(Token::RParen)?;
                self.skip_terminators();
            } else {
                // Single import: import "path" or import alias "path"
                imports.push(self.parse_single_import()?);
                self.skip_terminators();
            }
        }

        let mut decls = Vec::new();

        while self.peek().is_some() {
            // Skip terminators between declarations
            self.skip_terminators();

            if self.peek().is_none() {
                break;
            }

            // Check for grouped const: const ( ... )
            if self.peek() == Some(&Token::Const) {
                self.advance(); // consume 'const'
                if self.consume(&Token::LParen) {
                    // Grouped const block - use ConstBlock for iota support
                    let mut block_consts = Vec::new();
                    self.skip_terminators();
                    while self.peek() != Some(&Token::RParen) {
                        let const_decl = self.parse_const_in_group()?;
                        block_consts.push(const_decl);
                        self.skip_terminators();
                    }
                    self.expect(Token::RParen)?;
                    decls.push(Decl::ConstBlock(block_consts));
                    continue;
                } else {
                    // Single const - need to parse it, but we already consumed 'const'
                    // So call a helper that doesn't expect 'const' at the start
                    let const_decl = self.parse_const_after_keyword()?;
                    decls.push(Decl::Const(const_decl));
                    continue;
                }
            }

            decls.push(self.parse_decl()?);
        }

        Ok(File {
            package,
            imports,
            decls,
            comments: std::mem::take(&mut self.comments),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::syntax::FileId;

    #[test]
    fn test_parse_function() {
        let source = "func add(x int, y int) int { return x + y }";
        let mut parser = Parser::new(source, FileId(0));
        let func = parser.parse_func_decl().expect("failed to parse function");

        assert_eq!(func.name, "add");
        assert_eq!(func.params.len(), 2);
        assert_eq!(func.params[0].name, "x");
        assert_eq!(func.params[0].ty.name, "int");
        assert_eq!(func.params[1].name, "y");
        assert_eq!(func.return_types.len(), 1);
        assert_eq!(func.return_types[0].name, "int");
        assert_eq!(func.body.stmts.len(), 1);
    }

    #[test]
    fn test_parse_generic_function() {
        let source = "func identity[T any](x T) T { return x }";
        let mut parser = Parser::new(source, FileId(0));
        let func = parser
            .parse_func_decl()
            .expect("failed to parse generic function");

        assert_eq!(func.name, "identity");
        assert_eq!(func.generics.len(), 1);
        assert_eq!(func.generics[0].name, "T");
        assert_eq!(func.generics[0].constraint, "any");
        assert_eq!(func.params[0].ty.name, "T");
    }

    #[test]
    fn test_parse_enum() {
        let source = r#"type Result[T any, E any] enum {
            Ok T
            Err E
        }"#;
        let mut parser = Parser::new(source, FileId(0));
        let type_decl = parser.parse_type_decl().expect("failed to parse enum type");

        assert_eq!(type_decl.name, "Result");
        assert_eq!(type_decl.generics.len(), 2);
        assert_eq!(type_decl.generics[0].name, "T");
        assert_eq!(type_decl.generics[0].constraint, "any");
        assert_eq!(type_decl.generics[1].name, "E");
        assert_eq!(type_decl.generics[1].constraint, "any");

        match type_decl.kind {
            TypeKind::Enum { variants } => {
                assert_eq!(variants.len(), 2);

                match &variants[0] {
                    EnumVariant::Single { name, ty, .. } => {
                        assert_eq!(name, "Ok");
                        assert_eq!(ty.name, "T");
                    }
                    _ => panic!("Expected single variant"),
                }

                match &variants[1] {
                    EnumVariant::Single { name, ty, .. } => {
                        assert_eq!(name, "Err");
                        assert_eq!(ty.name, "E");
                    }
                    _ => panic!("Expected single variant"),
                }
            }
            _ => panic!("Expected enum"),
        }
    }

    #[test]
    fn test_parse_complete_file() {
        let source = r#"
            type Colour enum {
                Red
                Green
                Blue
            }

            func main() {
                colour := Colour.Red
                return colour
            }
        "#;
        let mut parser = Parser::new(source, FileId(0));
        let file = parser.parse_file().expect("failed to parse complete file");

        assert_eq!(file.decls.len(), 2);
        assert!(matches!(file.decls[0], Decl::Type(_)));
        assert!(matches!(file.decls[1], Decl::Func(_)));
    }

    #[test]
    fn test_parse_function_with_semicolons() {
        let source = "func add(x int, y int) int { c := x + y; return c }";
        let mut parser = Parser::new(source, FileId(0));
        let func = parser
            .parse_func_decl()
            .expect("failed to parse function with semicolons");

        assert_eq!(func.name, "add");
        assert_eq!(func.body.stmts.len(), 2);
    }

    #[test]
    fn test_parse_grouped_imports() {
        let source = r#"
            import (
                "fmt"
                "net/http"
            )
            func main() {}
        "#;
        let mut parser = Parser::new(source, FileId(0));
        let file = parser
            .parse_file()
            .expect("failed to parse grouped imports");

        assert_eq!(file.imports.len(), 2);
        assert_eq!(file.imports[0].path, "fmt");
        assert_eq!(file.imports[0].alias, None);
        assert_eq!(file.imports[1].path, "net/http");
        assert_eq!(file.imports[1].alias, None);
    }

    #[test]
    fn test_parse_aliased_imports() {
        let source = r#"
            import (
                "fmt"
                myHttp "net/http"
                "sop:util/helpers"
                h "sop:util/helpers"
            )
            func main() {}
        "#;
        let mut parser = Parser::new(source, FileId(0));
        let file = parser
            .parse_file()
            .expect("failed to parse aliased imports");

        assert_eq!(file.imports.len(), 4);

        assert_eq!(file.imports[0].path, "fmt");
        assert_eq!(file.imports[0].alias, None);

        assert_eq!(file.imports[1].path, "net/http");
        assert_eq!(file.imports[1].alias, Some("myHttp".to_string()));

        assert_eq!(file.imports[2].path, "sop:util/helpers");
        assert_eq!(file.imports[2].alias, None);

        assert_eq!(file.imports[3].path, "sop:util/helpers");
        assert_eq!(file.imports[3].alias, Some("h".to_string()));
    }

    #[test]
    fn test_parse_single_aliased_import() {
        let source = r#"
            import myFmt "fmt"
            func main() {}
        "#;
        let mut parser = Parser::new(source, FileId(0));
        let file = parser
            .parse_file()
            .expect("failed to parse single aliased import");

        assert_eq!(file.imports.len(), 1);
        assert_eq!(file.imports[0].path, "fmt");
        assert_eq!(file.imports[0].alias, Some("myFmt".to_string()));
    }
}
