use crate::ast::*;
use crate::lexer::{Token, TokenWithPos};

// ── Error type ────────────────────────────────────────────────────────────────

#[derive(Debug)]
pub struct ParseError {
    pub message: String,
    pub line: usize,
}

impl ParseError {
    fn new(message: impl Into<String>, line: usize) -> Self {
        Self {
            message: message.into(),
            line,
        }
    }
}

// ── Parser struct ─────────────────────────────────────────────────────────────

pub struct Parser {
    tokens: Vec<TokenWithPos>,
    pos: usize,
    no_struct_literal: bool,
}

impl Parser {
    pub fn new(tokens: Vec<TokenWithPos>) -> Self {
        Self {
            tokens,
            pos: 0,
            no_struct_literal: false,
        }
    }

    // ── Cursor helpers ────────────────────────────────────────────────────────

    fn peek(&self) -> &Token {
        let mut i = self.pos;
        while i < self.tokens.len() {
            if !matches!(self.tokens[i].token, Token::Newline) {
                return &self.tokens[i].token;
            }
            i += 1;
        }
        &Token::Eof
    }

    fn peek_pos(&self) -> (usize, usize) {
        let mut i = self.pos;
        while i < self.tokens.len() {
            if !matches!(self.tokens[i].token, Token::Newline) {
                return (self.tokens[i].line, self.tokens[i].col);
            }
            i += 1;
        }
        (0, 0)
    }

    fn span_here(&self) -> Span {
        let (line, col) = self.peek_pos();
        Span::new(line, col)
    }

    fn advance(&mut self) -> &Token {
        while self.pos < self.tokens.len() && matches!(self.tokens[self.pos].token, Token::Newline)
        {
            self.pos += 1;
        }
        if self.pos < self.tokens.len() {
            let tok = &self.tokens[self.pos].token;
            self.pos += 1;
            tok
        } else {
            &Token::Eof
        }
    }

    fn expect(&mut self, expected: &Token) -> Result<(), ParseError> {
        let (line, _) = self.peek_pos();
        let tok = self.peek().clone();
        if std::mem::discriminant(&tok) == std::mem::discriminant(expected) {
            self.advance();
            Ok(())
        } else {
            Err(ParseError::new(
                format!("'{:?}' 예상, '{:?}' 발견", expected, tok),
                line,
            ))
        }
    }

    fn is_at_end(&self) -> bool {
        matches!(self.peek(), Token::Eof)
    }

    // ── Top-level parse ───────────────────────────────────────────────────────

    pub fn parse(&mut self) -> Result<Program, ParseError> {
        let mut stmts = Vec::new();
        while !self.is_at_end() {
            stmts.push(self.parse_stmt()?);
        }
        Ok(Program::new(stmts))
    }

    // ── Statement dispatch ────────────────────────────────────────────────────

    fn parse_stmt(&mut self) -> Result<Stmt, ParseError> {
        let span = self.span_here();
        match self.peek().clone() {
            Token::함수 => self.parse_func_def(),
            Token::변수 => {
                self.advance();
                self.parse_var_decl(true, span)
            }
            Token::상수 => {
                self.advance();
                self.parse_var_decl(false, span)
            }
            Token::만약 => self.parse_if_stmt(),
            Token::반복 => self.parse_for_loop(),
            Token::동안 => self.parse_while_loop(),
            Token::반환 => {
                self.advance();
                if self.is_at_end()
                    || matches!(self.peek(), Token::RBrace | Token::Newline | Token::Eof)
                {
                    Ok(Stmt::new(StmtKind::Return(None), span))
                } else {
                    let expr = self.parse_expr()?;
                    Ok(Stmt::new(StmtKind::Return(Some(expr)), span))
                }
            }
            Token::멈춰 => {
                self.advance();
                Ok(Stmt::new(StmtKind::Break, span))
            }
            Token::계속 => {
                self.advance();
                Ok(Stmt::new(StmtKind::Continue, span))
            }
            Token::구조 => self.parse_struct_def(),
            Token::시도 => self.parse_try_catch(),
            Token::포함 => {
                self.advance();
                let (line, _) = self.peek_pos();
                match self.advance().clone() {
                    Token::StringLiteral(path) => Ok(Stmt::new(StmtKind::Import(path), span)),
                    tok => Err(ParseError::new(
                        format!("포함 뒤에 문자열 경로 필요, '{:?}' 발견", tok),
                        line,
                    )),
                }
            }
            Token::맞춤 => self.parse_match(),
            Token::구현 => self.parse_impl_block(),
            Token::열거 => self.parse_enum_def(),
            _ => {
                let expr = self.parse_expr()?;
                match self.peek().clone() {
                    Token::이면 | Token::만약 => {
                        self.advance();
                        self.parse_if_with_cond(span, expr)
                    }
                    Token::동안 => {
                        self.advance();
                        self.parse_while_with_cond(span, expr)
                    }
                    _ => Ok(Stmt::new(StmtKind::ExprStmt(expr), span)),
                }
            }
        }
    }

    // ── Function definition ───────────────────────────────────────────────────

    fn parse_func_def(&mut self) -> Result<Stmt, ParseError> {
        let span = self.span_here();
        self.advance();

        let name = match self.advance().clone() {
            Token::Identifier(n) => n,
            tok => {
                return Err(ParseError::new(
                    format!("함수 이름 예상, '{:?}' 발견", tok),
                    span.line,
                ));
            }
        };

        // generic type params <T, U, ...> — consumed and ignored at runtime
        if matches!(self.peek(), Token::Lt) {
            self.advance();
            while !matches!(self.peek(), Token::Gt | Token::Eof) {
                self.advance();
            }
            self.expect(&Token::Gt)?;
        }

        self.expect(&Token::LParen)?;

        let mut params: Vec<(String, Type)> = Vec::new();
        while !matches!(self.peek(), Token::RParen | Token::Eof) {
            let param_name = match self.advance().clone() {
                Token::Identifier(n) => n,
                tok => {
                    return Err(ParseError::new(
                        format!("매개변수 이름 예상, '{:?}' 발견", tok),
                        span.line,
                    ));
                }
            };
            self.expect(&Token::Colon)?;
            let ty = self.parse_type()?;
            params.push((param_name, ty));
            if matches!(self.peek(), Token::Comma) {
                self.advance();
            }
        }

        self.expect(&Token::RParen)?;

        let return_type = if matches!(self.peek(), Token::Arrow) {
            self.advance();
            Some(self.parse_type()?)
        } else {
            None
        };

        let body = self.parse_block()?;

        Ok(Stmt::new(
            StmtKind::FuncDef {
                name,
                params,
                return_type,
                body,
            },
            span,
        ))
    }

    // ── Variable declaration ──────────────────────────────────────────────────

    fn parse_var_decl(&mut self, mutable: bool, span: Span) -> Result<Stmt, ParseError> {
        let name = match self.advance().clone() {
            Token::Identifier(n) => n,
            tok => {
                return Err(ParseError::new(
                    format!("변수 이름 예상, '{:?}' 발견", tok),
                    span.line,
                ));
            }
        };

        let ty = if matches!(self.peek(), Token::Colon) {
            self.advance();
            Some(self.parse_type()?)
        } else {
            None
        };

        self.expect(&Token::Eq)?;
        let value = self.parse_expr()?;

        Ok(Stmt::new(
            StmtKind::VarDecl {
                name,
                ty,
                value,
                mutable,
            },
            span,
        ))
    }

    // ── If statement ──────────────────────────────────────────────────────────

    fn parse_if_stmt(&mut self) -> Result<Stmt, ParseError> {
        let span = self.span_here();
        self.advance();
        self.no_struct_literal = true;
        let cond = self.parse_expr()?;
        self.no_struct_literal = false;
        if matches!(self.peek(), Token::이면) {
            self.advance();
        }
        self.parse_if_with_cond(span, cond)
    }

    fn parse_if_with_cond(&mut self, span: Span, cond: Expr) -> Result<Stmt, ParseError> {
        let then_block = self.parse_block()?;

        let else_block = if matches!(self.peek(), Token::아니면) {
            self.advance();
            if matches!(self.peek(), Token::만약) {
                // SVO else-if: 아니면 만약 expr { }
                let nested_if = self.parse_if_stmt()?;
                Some(vec![nested_if])
            } else if matches!(self.peek(), Token::LBrace) {
                // else block: 아니면 { }
                Some(self.parse_block()?)
            } else {
                // SOV else-if: 아니면 expr 만약 { }
                let else_span = self.span_here();
                self.no_struct_literal = true;
                let else_cond = self.parse_expr()?;
                self.no_struct_literal = false;
                if matches!(self.peek(), Token::이면 | Token::만약) {
                    self.advance();
                    let nested_if = self.parse_if_with_cond(else_span, else_cond)?;
                    Some(vec![nested_if])
                } else {
                    let err_line = self.span_here().line;
                    return Err(ParseError::new(
                        "아니면 뒤에 '이면', '만약' 또는 '{' 필요",
                        err_line,
                    ));
                }
            }
        } else {
            None
        };

        Ok(Stmt::new(
            StmtKind::If {
                cond,
                then_block,
                else_block,
            },
            span,
        ))
    }

    // ── For loop ──────────────────────────────────────────────────────────────

    fn parse_for_loop(&mut self) -> Result<Stmt, ParseError> {
        let span = self.span_here();
        self.advance();

        // for-in: 반복 변수이름 안에서 iterable { }
        if let Token::Identifier(name) = self.peek().clone() {
            let saved_pos = self.pos;
            self.advance();
            if matches!(self.peek(), Token::안에서) {
                self.advance();
                self.no_struct_literal = true;
                let iterable = self.parse_expr()?;
                self.no_struct_literal = false;
                let body = self.parse_block()?;
                return Ok(Stmt::new(
                    StmtKind::ForIn {
                        var_name: name,
                        iterable,
                        body,
                    },
                    span,
                ));
            }
            self.pos = saved_pos;
        }

        let init_span = self.span_here();
        let init = if matches!(self.peek(), Token::변수) {
            self.advance();
            self.parse_var_decl(true, init_span)?
        } else if matches!(self.peek(), Token::상수) {
            self.advance();
            self.parse_var_decl(false, init_span)?
        } else {
            let expr = self.parse_expr()?;
            Stmt::new(StmtKind::ExprStmt(expr), init_span)
        };

        self.expect(&Token::Semicolon)?;
        let cond = self.parse_expr()?;
        self.expect(&Token::Semicolon)?;

        let step_span = self.span_here();
        let step_expr = self.parse_expr()?;
        let step = Stmt::new(StmtKind::ExprStmt(step_expr), step_span);

        let body = self.parse_block()?;

        Ok(Stmt::new(
            StmtKind::ForLoop {
                init: Box::new(init),
                cond,
                step: Box::new(step),
                body,
            },
            span,
        ))
    }

    // ── While loop ────────────────────────────────────────────────────────────

    fn parse_while_loop(&mut self) -> Result<Stmt, ParseError> {
        let span = self.span_here();
        self.advance();
        self.no_struct_literal = true;
        let cond = self.parse_expr()?;
        self.no_struct_literal = false;
        self.parse_while_with_cond(span, cond)
    }

    fn parse_while_with_cond(&mut self, span: Span, cond: Expr) -> Result<Stmt, ParseError> {
        let body = self.parse_block()?;
        Ok(Stmt::new(StmtKind::WhileLoop { cond, body }, span))
    }

    // ── Block ─────────────────────────────────────────────────────────────────

    fn parse_block(&mut self) -> Result<Vec<Stmt>, ParseError> {
        self.expect(&Token::LBrace)?;
        let mut stmts = Vec::new();
        while !matches!(self.peek(), Token::RBrace | Token::Eof) {
            stmts.push(self.parse_stmt()?);
        }
        self.expect(&Token::RBrace)?;
        Ok(stmts)
    }

    // ── Expression parsing (precedence climbing) ──────────────────────────────

    fn parse_expr(&mut self) -> Result<Expr, ParseError> {
        self.parse_pipe()
    }

    fn parse_pipe(&mut self) -> Result<Expr, ParseError> {
        let mut left = self.parse_assignment()?;
        while matches!(self.peek(), Token::PipeGt) {
            self.advance();
            let right = self.parse_assignment()?;
            left = match right {
                Expr::Call { name, mut args } => {
                    args.insert(0, left);
                    Expr::Call { name, args }
                }
                Expr::Identifier(name) => Expr::Call {
                    name,
                    args: vec![left],
                },
                _ => {
                    let (line, _) = self.peek_pos();
                    return Err(ParseError::new(
                        "|> 오른쪽에 함수 이름 또는 호출 필요",
                        line,
                    ));
                }
            };
        }
        Ok(left)
    }

    fn parse_assignment(&mut self) -> Result<Expr, ParseError> {
        let left = self.parse_or()?;

        let (line, _) = self.peek_pos();
        match self.peek().clone() {
            Token::Eq => {
                self.advance();
                let value = self.parse_assignment()?;
                match left {
                    Expr::Identifier(name) => {
                        return Ok(Expr::Assign {
                            name,
                            value: Box::new(value),
                        });
                    }
                    Expr::Index { object, index } => {
                        return Ok(Expr::IndexAssign {
                            object,
                            index,
                            value: Box::new(value),
                        });
                    }
                    Expr::FieldAccess { object, field } => {
                        return Ok(Expr::FieldAssign {
                            object,
                            field,
                            value: Box::new(value),
                        });
                    }
                    _ => {}
                }
                Err(ParseError::new("할당 대상이 올바르지 않습니다", line))
            }
            Token::PlusEq | Token::MinusEq | Token::StarEq | Token::SlashEq => {
                let op_tok = self.advance().clone();
                let rhs = self.parse_assignment()?;
                if let Expr::Identifier(ref name) = left {
                    let op = match op_tok {
                        Token::PlusEq => BinaryOpKind::Add,
                        Token::MinusEq => BinaryOpKind::Sub,
                        Token::StarEq => BinaryOpKind::Mul,
                        Token::SlashEq => BinaryOpKind::Div,
                        _ => unreachable!(),
                    };
                    let compound = Expr::BinaryOp {
                        op,
                        left: Box::new(left.clone()),
                        right: Box::new(rhs),
                    };
                    return Ok(Expr::Assign {
                        name: name.clone(),
                        value: Box::new(compound),
                    });
                }
                Err(ParseError::new("복합 할당 대상이 올바르지 않습니다", line))
            }
            _ => Ok(left),
        }
    }

    fn parse_or(&mut self) -> Result<Expr, ParseError> {
        let mut left = self.parse_and()?;
        while matches!(self.peek(), Token::PipePipe) {
            self.advance();
            let right = self.parse_and()?;
            left = Expr::BinaryOp {
                op: BinaryOpKind::Or,
                left: Box::new(left),
                right: Box::new(right),
            };
        }
        Ok(left)
    }

    fn parse_and(&mut self) -> Result<Expr, ParseError> {
        let mut left = self.parse_comparison()?;
        while matches!(self.peek(), Token::AmpAmp) {
            self.advance();
            let right = self.parse_comparison()?;
            left = Expr::BinaryOp {
                op: BinaryOpKind::And,
                left: Box::new(left),
                right: Box::new(right),
            };
        }
        Ok(left)
    }

    fn parse_comparison(&mut self) -> Result<Expr, ParseError> {
        let mut left = self.parse_addition()?;

        if matches!(self.peek(), Token::DotDot) {
            self.advance();
            let right = self.parse_addition()?;
            return Ok(Expr::Range {
                start: Box::new(left),
                end: Box::new(right),
            });
        }

        loop {
            let op = match self.peek() {
                Token::EqEq => BinaryOpKind::Eq,
                Token::BangEq => BinaryOpKind::NotEq,
                Token::Lt => BinaryOpKind::Lt,
                Token::Gt => BinaryOpKind::Gt,
                Token::LtEq => BinaryOpKind::LtEq,
                Token::GtEq => BinaryOpKind::GtEq,
                _ => break,
            };
            self.advance();
            let right = self.parse_addition()?;
            left = Expr::BinaryOp {
                op,
                left: Box::new(left),
                right: Box::new(right),
            };
        }
        Ok(left)
    }

    fn parse_addition(&mut self) -> Result<Expr, ParseError> {
        let mut left = self.parse_multiplication()?;
        loop {
            let op = match self.peek() {
                Token::Plus => BinaryOpKind::Add,
                Token::Minus => BinaryOpKind::Sub,
                _ => break,
            };
            self.advance();
            let right = self.parse_multiplication()?;
            left = Expr::BinaryOp {
                op,
                left: Box::new(left),
                right: Box::new(right),
            };
        }
        Ok(left)
    }

    fn parse_multiplication(&mut self) -> Result<Expr, ParseError> {
        let mut left = self.parse_unary()?;
        loop {
            let op = match self.peek() {
                Token::Star => BinaryOpKind::Mul,
                Token::Slash => BinaryOpKind::Div,
                Token::Percent => BinaryOpKind::Mod,
                _ => break,
            };
            self.advance();
            let right = self.parse_unary()?;
            left = Expr::BinaryOp {
                op,
                left: Box::new(left),
                right: Box::new(right),
            };
        }
        Ok(left)
    }

    fn parse_unary(&mut self) -> Result<Expr, ParseError> {
        match self.peek().clone() {
            Token::Minus => {
                self.advance();
                let expr = self.parse_unary()?;
                Ok(Expr::UnaryOp {
                    op: UnaryOpKind::Neg,
                    expr: Box::new(expr),
                })
            }
            Token::Bang => {
                self.advance();
                let expr = self.parse_unary()?;
                Ok(Expr::UnaryOp {
                    op: UnaryOpKind::Not,
                    expr: Box::new(expr),
                })
            }
            _ => self.parse_primary(),
        }
    }

    fn parse_string_literal_expr(&self, literal: String, line: usize) -> Result<Expr, ParseError> {
        if !literal.contains("${") {
            return Ok(Expr::StringLiteral(literal));
        }

        let (template, exprs) = self.desugar_interpolation(&literal, line)?;
        let mut args = Vec::with_capacity(exprs.len() + 1);
        args.push(Expr::StringLiteral(template));
        args.extend(exprs);

        Ok(Expr::Call {
            name: "형식".to_string(),
            args,
        })
    }

    fn desugar_interpolation(
        &self,
        literal: &str,
        line: usize,
    ) -> Result<(String, Vec<Expr>), ParseError> {
        let chars: Vec<char> = literal.chars().collect();
        let mut template = String::new();
        let mut exprs = Vec::new();
        let mut index = 0;

        while index < chars.len() {
            if chars[index] == '$' && chars.get(index + 1) == Some(&'{') {
                index += 2;
                let start = index;
                while index < chars.len() && chars[index] != '}' {
                    index += 1;
                }

                if index == chars.len() {
                    return Err(ParseError::new("문자열 보간 닫는 '}' 필요", line));
                }

                let expr_source: String = chars[start..index].iter().collect();
                let expr = self.parse_interpolation_expr(&expr_source, line)?;
                template.push_str(&format!("{{{}}}", exprs.len()));
                exprs.push(expr);
                index += 1;
                continue;
            }

            template.push(chars[index]);
            index += 1;
        }

        Ok((template, exprs))
    }

    fn parse_interpolation_expr(&self, expr_source: &str, line: usize) -> Result<Expr, ParseError> {
        let trimmed = expr_source.trim();
        if trimmed.is_empty() {
            return Err(ParseError::new("문자열 보간 식이 비어 있습니다", line));
        }

        let mut parser = Parser::new(crate::lexer::tokenize(trimmed));
        let expr = parser.parse_expr()?;
        if !matches!(parser.peek(), Token::Eof) {
            return Err(ParseError::new(
                "문자열 보간 식 파싱 실패: 예상치 못한 토큰",
                line,
            ));
        }
        Ok(expr)
    }

    fn parse_primary(&mut self) -> Result<Expr, ParseError> {
        let (line, _) = self.peek_pos();
        let mut expr = match self.peek().clone() {
            Token::IntLiteral(n) => {
                self.advance();
                Expr::IntLiteral(n)
            }
            Token::FloatLiteral(f) => {
                self.advance();
                Expr::FloatLiteral(f)
            }
            Token::StringLiteral(s) => {
                self.advance();
                self.parse_string_literal_expr(s, line)?
            }
            Token::참 => {
                self.advance();
                Expr::BoolLiteral(true)
            }
            Token::거짓 => {
                self.advance();
                Expr::BoolLiteral(false)
            }
            Token::없음 => {
                self.advance();
                Expr::NullLiteral
            }
            Token::LBracket => {
                self.advance();
                let mut elems = Vec::new();
                while !matches!(self.peek(), Token::RBracket | Token::Eof) {
                    elems.push(self.parse_expr()?);
                    if matches!(self.peek(), Token::Comma) {
                        self.advance();
                    }
                }
                self.expect(&Token::RBracket)?;
                Expr::ArrayLiteral(elems)
            }
            Token::Identifier(name) => {
                self.advance();
                if matches!(self.peek(), Token::ColonColon) {
                    self.advance();
                    let variant = match self.advance().clone() {
                        Token::Identifier(v) => v,
                        tok => {
                            return Err(ParseError::new(
                                format!("열거형 변형 이름 예상, '{:?}' 발견", tok),
                                line,
                            ));
                        }
                    };
                    Expr::Identifier(format!("{}::{}", name, variant))
                } else if matches!(self.peek(), Token::LParen) {
                    self.advance();
                    let mut args = Vec::new();
                    while !matches!(self.peek(), Token::RParen | Token::Eof) {
                        args.push(self.parse_expr()?);
                        if matches!(self.peek(), Token::Comma) {
                            self.advance();
                        }
                    }
                    self.expect(&Token::RParen)?;
                    Expr::Call { name, args }
                } else if matches!(self.peek(), Token::LBrace) && !self.no_struct_literal {
                    self.advance();
                    let mut fields = Vec::new();
                    while !matches!(self.peek(), Token::RBrace | Token::Eof) {
                        let fname = match self.advance().clone() {
                            Token::Identifier(n) => n,
                            tok => {
                                return Err(ParseError::new(
                                    format!("필드 이름 예상, '{:?}' 발견", tok),
                                    line,
                                ));
                            }
                        };
                        self.expect(&Token::Colon)?;
                        let fval = self.parse_expr()?;
                        fields.push((fname, fval));
                        if matches!(self.peek(), Token::Comma) {
                            self.advance();
                        }
                    }
                    self.expect(&Token::RBrace)?;
                    Expr::StructLiteral { name, fields }
                } else {
                    Expr::Identifier(name)
                }
            }
            Token::출력 => {
                self.advance();
                self.expect(&Token::LParen)?;
                let mut args = Vec::new();
                while !matches!(self.peek(), Token::RParen | Token::Eof) {
                    args.push(self.parse_expr()?);
                    if matches!(self.peek(), Token::Comma) {
                        self.advance();
                    }
                }
                self.expect(&Token::RParen)?;
                Expr::Call {
                    name: "출력".to_string(),
                    args,
                }
            }
            Token::입력 => {
                self.advance();
                self.expect(&Token::LParen)?;
                let mut args = Vec::new();
                while !matches!(self.peek(), Token::RParen | Token::Eof) {
                    args.push(self.parse_expr()?);
                    if matches!(self.peek(), Token::Comma) {
                        self.advance();
                    }
                }
                self.expect(&Token::RParen)?;
                Expr::Call {
                    name: "입력".to_string(),
                    args,
                }
            }
            Token::LParen => {
                self.advance();
                let e = self.parse_expr()?;
                if matches!(self.peek(), Token::Comma) {
                    let mut elems = vec![e];
                    while matches!(self.peek(), Token::Comma) {
                        self.advance();
                        if matches!(self.peek(), Token::RParen) {
                            break;
                        }
                        elems.push(self.parse_expr()?);
                    }
                    self.expect(&Token::RParen)?;
                    Expr::TupleLiteral(elems)
                } else {
                    self.expect(&Token::RParen)?;
                    e
                }
            }
            Token::함수 => {
                self.advance();
                self.expect(&Token::LParen)?;
                let mut params = Vec::new();
                while !matches!(self.peek(), Token::RParen | Token::Eof) {
                    let pname = match self.advance().clone() {
                        Token::Identifier(n) => n,
                        tok => {
                            return Err(ParseError::new(
                                format!("람다 매개변수 이름 예상, '{:?}' 발견", tok),
                                line,
                            ));
                        }
                    };
                    let pty = if matches!(self.peek(), Token::Colon) {
                        self.advance();
                        Some(self.parse_type()?)
                    } else {
                        None
                    };
                    params.push((pname, pty));
                    if matches!(self.peek(), Token::Comma) {
                        self.advance();
                    }
                }
                self.expect(&Token::RParen)?;
                let body = self.parse_block()?;
                Expr::Lambda { params, body }
            }
            tok => {
                return Err(ParseError::new(
                    format!("표현식에서 예상치 못한 토큰: {:?}", tok),
                    line,
                ));
            }
        };

        // postfix: indexing, method call, field access
        loop {
            match self.peek().clone() {
                Token::LBracket => {
                    self.advance();
                    let index = self.parse_expr()?;
                    self.expect(&Token::RBracket)?;
                    expr = Expr::Index {
                        object: Box::new(expr),
                        index: Box::new(index),
                    };
                }
                Token::Dot => {
                    self.advance();
                    if let Token::IntLiteral(idx) = self.peek().clone() {
                        self.advance();
                        expr = Expr::TupleIndex {
                            object: Box::new(expr),
                            index: idx as usize,
                        };
                        continue;
                    }
                    let member = match self.advance().clone() {
                        Token::Identifier(n) => n,
                        Token::포함 => "포함".to_string(),
                        tok => {
                            return Err(ParseError::new(
                                format!("필드/메서드 이름 예상, '{:?}' 발견", tok),
                                line,
                            ));
                        }
                    };
                    if matches!(self.peek(), Token::LParen) {
                        self.advance();
                        let mut args = Vec::new();
                        while !matches!(self.peek(), Token::RParen | Token::Eof) {
                            args.push(self.parse_expr()?);
                            if matches!(self.peek(), Token::Comma) {
                                self.advance();
                            }
                        }
                        self.expect(&Token::RParen)?;
                        expr = Expr::MethodCall {
                            object: Box::new(expr),
                            method: member,
                            args,
                        };
                    } else {
                        expr = Expr::FieldAccess {
                            object: Box::new(expr),
                            field: member,
                        };
                    }
                }
                _ => break,
            }
        }

        Ok(expr)
    }

    // ── Type parsing ──────────────────────────────────────────────────────────

    fn parse_type(&mut self) -> Result<Type, ParseError> {
        let (line, _) = self.peek_pos();
        if matches!(self.peek(), Token::LParen) {
            self.advance();
            let mut types = Vec::new();
            while !matches!(self.peek(), Token::RParen | Token::Eof) {
                types.push(self.parse_type()?);
                if matches!(self.peek(), Token::Comma) {
                    self.advance();
                }
            }
            self.expect(&Token::RParen)?;
            return Ok(Type::튜플(types));
        }
        if matches!(self.peek(), Token::LBracket) {
            self.advance();
            let inner = self.parse_type()?;
            self.expect(&Token::RBracket)?;
            return Ok(Type::배열(Box::new(inner)));
        }
        match self.advance().clone() {
            Token::정수타입 => Ok(Type::정수),
            Token::실수타입 => Ok(Type::실수),
            Token::문자열타입 => Ok(Type::문자열),
            Token::불타입 => Ok(Type::불),
            Token::없음타입 | Token::없음 => Ok(Type::없음),
            Token::함수 => Ok(Type::함수타입),
            Token::Identifier(name) => Ok(Type::구조체(name)),
            tok => Err(ParseError::new(
                format!("타입 예상 (정수/실수/문자열/불/없음), '{:?}' 발견", tok),
                line,
            )),
        }
    }

    fn parse_struct_def(&mut self) -> Result<Stmt, ParseError> {
        let span = self.span_here();
        self.advance();
        let name = match self.advance().clone() {
            Token::Identifier(n) => n,
            tok => {
                return Err(ParseError::new(
                    format!("구조체 이름 예상, '{:?}' 발견", tok),
                    span.line,
                ));
            }
        };
        self.expect(&Token::LBrace)?;
        let mut fields = Vec::new();
        while !matches!(self.peek(), Token::RBrace | Token::Eof) {
            let fname = match self.advance().clone() {
                Token::Identifier(n) => n,
                tok => {
                    return Err(ParseError::new(
                        format!("필드 이름 예상, '{:?}' 발견", tok),
                        span.line,
                    ));
                }
            };
            self.expect(&Token::Colon)?;
            let ftype = self.parse_type()?;
            fields.push((fname, ftype));
            if matches!(self.peek(), Token::Comma) {
                self.advance();
            }
        }
        self.expect(&Token::RBrace)?;
        Ok(Stmt::new(StmtKind::StructDef { name, fields }, span))
    }

    fn parse_try_catch(&mut self) -> Result<Stmt, ParseError> {
        let span = self.span_here();
        self.advance();
        let try_block = self.parse_block()?;
        let (line, _) = self.peek_pos();
        match self.peek().clone() {
            Token::처리 => {
                self.advance();
                self.expect(&Token::LParen)?;
                let error_name = match self.advance().clone() {
                    Token::Identifier(n) => n,
                    tok => {
                        return Err(ParseError::new(
                            format!("에러 변수 이름 예상, '{:?}' 발견", tok),
                            line,
                        ));
                    }
                };
                self.expect(&Token::RParen)?;
                let catch_block = self.parse_block()?;
                Ok(Stmt::new(
                    StmtKind::TryCatch {
                        try_block,
                        error_name,
                        catch_block,
                    },
                    span,
                ))
            }
            tok => Err(ParseError::new(
                format!("'처리' 예상, '{:?}' 발견", tok),
                line,
            )),
        }
    }

    fn parse_match(&mut self) -> Result<Stmt, ParseError> {
        let span = self.span_here();
        self.advance();
        self.no_struct_literal = true;
        let expr = self.parse_or()?;
        self.no_struct_literal = false;
        self.expect(&Token::LBrace)?;
        let mut arms = Vec::new();
        while !matches!(self.peek(), Token::RBrace | Token::Eof) {
            let pattern = self.parse_pattern()?;
            self.expect(&Token::화살표이중)?;
            let body = if matches!(self.peek(), Token::LBrace) {
                self.parse_block()?
            } else {
                let s = self.parse_stmt()?;
                if matches!(self.peek(), Token::Comma) {
                    self.advance();
                }
                vec![s]
            };
            arms.push(MatchArm { pattern, body });
        }
        self.expect(&Token::RBrace)?;
        Ok(Stmt::new(StmtKind::Match { expr, arms }, span))
    }

    fn parse_pattern(&mut self) -> Result<Pattern, ParseError> {
        let (line, _) = self.peek_pos();
        match self.peek().clone() {
            Token::IntLiteral(n) => {
                self.advance();
                Ok(Pattern::IntLiteral(n))
            }
            Token::FloatLiteral(f) => {
                self.advance();
                Ok(Pattern::FloatLiteral(f))
            }
            Token::StringLiteral(s) => {
                self.advance();
                Ok(Pattern::StringLiteral(s))
            }
            Token::참 => {
                self.advance();
                Ok(Pattern::BoolLiteral(true))
            }
            Token::거짓 => {
                self.advance();
                Ok(Pattern::BoolLiteral(false))
            }
            Token::Identifier(name) if name == "_" => {
                self.advance();
                Ok(Pattern::Wildcard)
            }
            Token::Identifier(name) => {
                self.advance();
                Ok(Pattern::Identifier(name))
            }
            Token::LBracket => {
                self.advance();
                let mut pats = Vec::new();
                while !matches!(self.peek(), Token::RBracket | Token::Eof) {
                    pats.push(self.parse_pattern()?);
                    if matches!(self.peek(), Token::Comma) {
                        self.advance();
                    }
                }
                self.expect(&Token::RBracket)?;
                Ok(Pattern::ArrayPattern(pats))
            }
            tok => Err(ParseError::new(
                format!("패턴 예상, '{:?}' 발견", tok),
                line,
            )),
        }
    }

    fn parse_impl_block(&mut self) -> Result<Stmt, ParseError> {
        let span = self.span_here();
        self.advance();
        let struct_name = match self.advance().clone() {
            Token::Identifier(n) => n,
            tok => {
                return Err(ParseError::new(
                    format!("구조체 이름 예상, '{:?}' 발견", tok),
                    span.line,
                ));
            }
        };
        self.expect(&Token::LBrace)?;
        let mut methods = Vec::new();
        while !matches!(self.peek(), Token::RBrace | Token::Eof) {
            if matches!(self.peek(), Token::함수) {
                methods.push(self.parse_func_def()?);
            } else {
                break;
            }
        }
        self.expect(&Token::RBrace)?;
        Ok(Stmt::new(
            StmtKind::ImplBlock {
                struct_name,
                methods,
            },
            span,
        ))
    }

    fn parse_enum_def(&mut self) -> Result<Stmt, ParseError> {
        let span = self.span_here();
        self.advance();
        let name = match self.advance().clone() {
            Token::Identifier(n) => n,
            tok => {
                return Err(ParseError::new(
                    format!("열거형 이름 예상, '{:?}' 발견", tok),
                    span.line,
                ));
            }
        };
        self.expect(&Token::LBrace)?;
        let mut variants = Vec::new();
        while !matches!(self.peek(), Token::RBrace | Token::Eof) {
            match self.advance().clone() {
                Token::Identifier(v) => variants.push(v),
                tok => {
                    return Err(ParseError::new(
                        format!("열거형 변형 이름 예상, '{:?}' 발견", tok),
                        span.line,
                    ));
                }
            }
            if matches!(self.peek(), Token::Comma) {
                self.advance();
            }
        }
        self.expect(&Token::RBrace)?;
        Ok(Stmt::new(StmtKind::EnumDef { name, variants }, span))
    }
}

// ── Public entry point ────────────────────────────────────────────────────────

pub fn parse(tokens: Vec<TokenWithPos>) -> Result<Program, ParseError> {
    Parser::new(tokens).parse()
}

// ── Tests ─────────────────────────────────────────────────────────────────────

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

    fn parse_src(src: &str) -> Program {
        let tokens = tokenize(src);
        parse(tokens).expect("parse failed")
    }

    #[test]
    fn test_parse_func_def() {
        let src = "함수 더하기(가: 정수, 나: 정수) -> 정수 { 반환 가 + 나 }";
        let prog = parse_src(src);
        assert_eq!(prog.stmts.len(), 1);
        match &prog.stmts[0].kind {
            StmtKind::FuncDef {
                name,
                params,
                return_type,
                body,
            } => {
                assert_eq!(name, "더하기");
                assert_eq!(params.len(), 2);
                assert_eq!(params[0], ("가".to_string(), Type::정수));
                assert_eq!(params[1], ("나".to_string(), Type::정수));
                assert!(matches!(return_type, Some(Type::정수)));
                assert_eq!(body.len(), 1);
                assert!(matches!(body[0].kind, StmtKind::Return(Some(_))));
            }
            _ => panic!("Expected FuncDef"),
        }
    }

    #[test]
    fn test_parse_var_decl() {
        let src = "변수 나이 = 20";
        let prog = parse_src(src);
        assert_eq!(prog.stmts.len(), 1);
        match &prog.stmts[0].kind {
            StmtKind::VarDecl {
                name,
                ty,
                value,
                mutable,
            } => {
                assert_eq!(name, "나이");
                assert!(ty.is_none());
                assert!(matches!(value, Expr::IntLiteral(20)));
                assert!(*mutable);
            }
            _ => panic!("Expected VarDecl"),
        }
    }

    #[test]
    fn test_parse_if_else() {
        let src = "만약 x > 0 { 반환 x } 아니면 { 반환 -x }";
        let prog = parse_src(src);
        assert_eq!(prog.stmts.len(), 1);
        match &prog.stmts[0].kind {
            StmtKind::If {
                cond,
                then_block,
                else_block,
            } => {
                assert!(matches!(
                    cond,
                    Expr::BinaryOp {
                        op: BinaryOpKind::Gt,
                        ..
                    }
                ));
                assert_eq!(then_block.len(), 1);
                assert!(else_block.is_some());
                assert_eq!(else_block.as_ref().unwrap().len(), 1);
            }
            _ => panic!("Expected If"),
        }
    }

    #[test]
    fn test_parse_for_loop() {
        let src = "반복 변수 i = 0; i < 10; i += 1 { 출력(i) }";
        let prog = parse_src(src);
        assert_eq!(prog.stmts.len(), 1);
        match &prog.stmts[0].kind {
            StmtKind::ForLoop {
                init,
                cond,
                step: _,
                body,
            } => {
                assert!(matches!(&init.kind, StmtKind::VarDecl { name, .. } if name == "i"));
                assert!(matches!(
                    cond,
                    Expr::BinaryOp {
                        op: BinaryOpKind::Lt,
                        ..
                    }
                ));
                assert_eq!(body.len(), 1);
            }
            _ => panic!("Expected ForLoop"),
        }
    }

    #[test]
    fn test_expr_precedence() {
        let src = "3 + 5 * 2";
        let prog = parse_src(src);
        assert_eq!(prog.stmts.len(), 1);
        match &prog.stmts[0].kind {
            StmtKind::ExprStmt(Expr::BinaryOp { op, left, right }) => {
                assert_eq!(*op, BinaryOpKind::Add);
                assert!(matches!(left.as_ref(), Expr::IntLiteral(3)));
                match right.as_ref() {
                    Expr::BinaryOp { op, left, right } => {
                        assert_eq!(*op, BinaryOpKind::Mul);
                        assert!(matches!(left.as_ref(), Expr::IntLiteral(5)));
                        assert!(matches!(right.as_ref(), Expr::IntLiteral(2)));
                    }
                    _ => panic!("Expected inner BinaryOp(Mul)"),
                }
            }
            _ => panic!("Expected ExprStmt(BinaryOp(Add, ...))"),
        }
    }

    #[test]
    fn test_parse_while_loop() {
        let src = "동안 참 { 멈춰 }";
        let prog = parse_src(src);
        assert_eq!(prog.stmts.len(), 1);
        match &prog.stmts[0].kind {
            StmtKind::WhileLoop { cond, body } => {
                assert!(matches!(cond, Expr::BoolLiteral(true)));
                assert_eq!(body.len(), 1);
                assert!(matches!(body[0].kind, StmtKind::Break));
            }
            _ => panic!("Expected WhileLoop"),
        }
    }

    #[test]
    fn test_parse_sov_if_stmt() {
        let src = "x > 0 만약 { 반환 x } 아니면 { 반환 -x }";
        let prog = parse_src(src);
        assert_eq!(prog.stmts.len(), 1);
        match &prog.stmts[0].kind {
            StmtKind::If {
                cond,
                then_block,
                else_block,
            } => {
                assert!(matches!(
                    cond,
                    Expr::BinaryOp {
                        op: BinaryOpKind::Gt,
                        ..
                    }
                ));
                assert_eq!(then_block.len(), 1);
                assert!(else_block.is_some());
                assert_eq!(else_block.as_ref().unwrap().len(), 1);
            }
            _ => panic!("Expected If"),
        }
    }

    #[test]
    fn test_parse_sov_while_loop() {
        let src = "x > 0 동안 { x -= 1 }";
        let prog = parse_src(src);
        assert_eq!(prog.stmts.len(), 1);
        match &prog.stmts[0].kind {
            StmtKind::WhileLoop { cond, body } => {
                assert!(matches!(
                    cond,
                    Expr::BinaryOp {
                        op: BinaryOpKind::Gt,
                        ..
                    }
                ));
                assert_eq!(body.len(), 1);
                assert!(matches!(body[0].kind, StmtKind::ExprStmt(_)));
            }
            _ => panic!("Expected WhileLoop"),
        }
    }

    #[test]
    fn test_parse_imyeon_if_stmt() {
        let tokens = tokenize("만약 x > 0 이면 { 출력(x) }");
        let program = parse(tokens).unwrap();
        assert_eq!(program.stmts.len(), 1);
        assert!(matches!(program.stmts[0].kind, StmtKind::If { .. }));
    }

    #[test]
    fn test_parse_imyeon_else_if() {
        let tokens = tokenize(
            "만약 x > 0 이면 { 출력(1) } 아니면 x < 0 이면 { 출력(2) } 아니면 { 출력(0) }",
        );
        let program = parse(tokens).unwrap();
        assert_eq!(program.stmts.len(), 1);
        assert!(matches!(program.stmts[0].kind, StmtKind::If { .. }));
    }

    #[test]
    fn test_parse_sov_imyeon() {
        let tokens = tokenize("x > 0 이면 { 출력(x) }");
        let program = parse(tokens).unwrap();
        assert_eq!(program.stmts.len(), 1);
        assert!(matches!(program.stmts[0].kind, StmtKind::If { .. }));
    }

    #[test]
    fn test_parse_const_decl_with_type() {
        let src = "상수 최대값: 정수 = 100";
        let prog = parse_src(src);
        match &prog.stmts[0].kind {
            StmtKind::VarDecl {
                name,
                ty,
                value,
                mutable,
            } => {
                assert_eq!(name, "최대값");
                assert!(matches!(ty, Some(Type::정수)));
                assert!(matches!(value, Expr::IntLiteral(100)));
                assert!(!mutable);
            }
            _ => panic!("Expected VarDecl"),
        }
    }

    #[test]
    fn test_parse_func_call() {
        let src = "더하기(1, 2)";
        let prog = parse_src(src);
        match &prog.stmts[0].kind {
            StmtKind::ExprStmt(Expr::Call { name, args }) => {
                assert_eq!(name, "더하기");
                assert_eq!(args.len(), 2);
            }
            _ => panic!("Expected ExprStmt(Call)"),
        }
    }

    #[test]
    fn test_parse_else_if_chain() {
        let src = "만약 x > 10 { 출력(1) } 아니면 만약 x > 5 { 출력(2) } 아니면 { 출력(3) }";
        let prog = parse_src(src);
        assert_eq!(prog.stmts.len(), 1);
        match &prog.stmts[0].kind {
            StmtKind::If {
                else_block: Some(else_stmts),
                ..
            } => {
                assert_eq!(else_stmts.len(), 1);
                assert!(matches!(else_stmts[0].kind, StmtKind::If { .. }));
                if let StmtKind::If {
                    else_block: Some(inner_else),
                    ..
                } = &else_stmts[0].kind
                {
                    assert_eq!(inner_else.len(), 1);
                } else {
                    panic!("Expected inner else block");
                }
            }
            _ => panic!("Expected If with else-if chain"),
        }
    }

    #[test]
    fn test_parse_plain_string_literal() {
        let src = "\"일반 문자열\"";
        let prog = parse_src(src);
        match &prog.stmts[0].kind {
            StmtKind::ExprStmt(Expr::StringLiteral(s)) => assert_eq!(s, "일반 문자열"),
            _ => panic!("Expected ExprStmt(StringLiteral)"),
        }
    }

    #[test]
    fn test_parse_interpolated_string_in_var_decl() {
        let src = "변수 메시지 = \"이름: ${이름}, 나이: ${나이}\"";
        let prog = parse_src(src);
        match &prog.stmts[0].kind {
            StmtKind::VarDecl { value, .. } => match value {
                Expr::Call { name, args } => {
                    assert_eq!(name, "형식");
                    assert_eq!(args.len(), 3);
                    assert!(
                        matches!(&args[0], Expr::StringLiteral(template) if template == "이름: {0}, 나이: {1}")
                    );
                    assert!(matches!(&args[1], Expr::Identifier(name) if name == "이름"));
                    assert!(matches!(&args[2], Expr::Identifier(name) if name == "나이"));
                }
                _ => panic!("Expected interpolated string to desugar into Call"),
            },
            _ => panic!("Expected VarDecl"),
        }
    }

    #[test]
    fn test_parse_multiple_interpolations() {
        let src = "\"${a} + ${b}\"";
        let prog = parse_src(src);
        match &prog.stmts[0].kind {
            StmtKind::ExprStmt(Expr::Call { name, args }) => {
                assert_eq!(name, "형식");
                assert_eq!(args.len(), 3);
                assert!(
                    matches!(&args[0], Expr::StringLiteral(template) if template == "{0} + {1}")
                );
                assert!(matches!(&args[1], Expr::Identifier(name) if name == "a"));
                assert!(matches!(&args[2], Expr::Identifier(name) if name == "b"));
            }
            _ => panic!("Expected ExprStmt(Call)"),
        }
    }

    #[test]
    fn test_parse_interpolation_with_binary_expression() {
        let src = "\"결과: ${1 + 2}\"";
        let prog = parse_src(src);
        match &prog.stmts[0].kind {
            StmtKind::ExprStmt(Expr::Call { name, args }) => {
                assert_eq!(name, "형식");
                assert_eq!(args.len(), 2);
                assert!(
                    matches!(&args[0], Expr::StringLiteral(template) if template == "결과: {0}")
                );
                assert!(matches!(
                    &args[1],
                    Expr::BinaryOp {
                        op: BinaryOpKind::Add,
                        ..
                    }
                ));
            }
            _ => panic!("Expected ExprStmt(Call)"),
        }
    }

    #[test]
    fn test_span_tracking() {
        let src = "변수 나이 = 20";
        let prog = parse_src(src);
        assert_eq!(prog.stmts[0].span.line, 1);
    }
}
