// rasm-core/src/parser/mod.rs
//
//! # Парсер RASM (Pass 2)
//!
//! ## Общая схема работы
//!
//! ```text
//! Токены (Vec<Token>)
//!     │
//!     ├─► Pass 1 (pass1.rs) — один быстрый проход, строим LabelTable
//!     │       { "main" -> 0, ".loop" -> 3, "_start" -> 0 }
//!     │
//!     └─► Pass 2 (этот файл) — строим AST, используя LabelTable
//!             └─► AST { program: [Label, Instruction, Directive, ...] }
//! ```
//!
//! ## Что умеет парсить Pass 2
//!
//! | Паттерн токенов                        | Результат                   |
//! |----------------------------------------|-----------------------------|
//! | `Ident ':'`                            | `Statement::Label`          |
//! | `Mnemonic op1, op2`                    | `Statement::Instruction`    |
//! | `Dot Ident operands...`                | `Statement::Directive`      |
//! | `Newline`                              | пропуск (пустая строка)     |
//!
//! ## Операнды инструкций
//!
//! | Синтаксис                              | `Operand` вариант           |
//! |----------------------------------------|-----------------------------|
//! | `rax`, `xmm0`                          | `Operand::Register`         |
//! | `42`, `0xFF`                           | `Operand::Immediate`        |
//! | `[rax]`, `[rax + rbx*4 + 8]`           | `Operand::Memory`           |
//! | `qword ptr [rax]`                      | `Operand::Memory` + DataType|
//! | `my_label` (в jmp/call/je/...)         | `Operand::Label`            |
//!
//! ## Адресация памяти `[base + index * scale + disp]`
//!
//! Парсер разбирает полную форму SIB-адресации x86_64:
//! - `base`        — любой регистр ([`Registers`])
//! - `index`       — только GPR ([`GPRs`])  
//! - `scale`       — литерал 1, 2, 4 или 8
//! - `displacement` — знаковое 32-битное смещение
//!
//! Примеры: `[rsp]`, `[rbp - 8]`, `[rax + rcx*4]`, `[rip + some_var]`

pub mod ast;
pub mod err;
pub mod pass1;

use crate::{
    isa::{
        GPRs, Instruction, MemoryAddress, Operand, Registers, Scale,
        directive::{Directive, DirectiveKind, DirectiveOperand},
    },
    lexer::token::{Span, Token, TokenKind},
    str_pool::StrPool,
};

use ast::{AST, Statement};
use err::{ParserError, ParserErrorKind};

/// # Парсер
///
/// Хранит состояние второго прохода: срез токенов, текущую позицию курсора,
/// таблицу меток из Pass 1 и накопленные ошибки.
pub struct Parser<'a> {
    /// Все токены, полученные от лексера.
    tokens: &'a [Token],

    /// Текущая позиция в `tokens`. Указывает на токен, который будет обработан следующим.
    cursor: usize,

    /// Пул строк компилятора (нужен для интернирования новых StrId в директивах).
    str_pool: &'a mut StrPool,

    /// Найденные синтаксические ошибки. Парсер не останавливается на первой ошибке —
    /// он фиксирует её и пытается продолжить разбор следующей строки.
    pub errors: Vec<ParserError>,
}

impl<'a> Parser<'a> {
    /// Создаёт парсер и сразу запускает Pass 1 для сбора меток.
    pub fn new(tokens: &'a [Token], str_pool: &'a mut StrPool) -> Self {
        Self {
            tokens,
            cursor: 0,
            str_pool,
            errors: Vec::new(),
        }
    }

    /// Запускает полный разбор токенов и возвращает AST.
    /// При наличии ошибок они будут в `self.errors`, но AST тоже вернётся —
    /// с теми узлами, которые удалось разобрать.
    pub fn parse(&mut self) -> AST {
        let mut ast = AST::new();

        loop {
            // Пропускаем пустые строки между инструкциями
            self.skip_newlines();

            // Конец файла
            if self.peek_kind() == TokenKind::End {
                break;
            }

            // Разбираем одно утверждение
            match self.parse_statement() {
                Some(stmt) => ast.program.push(stmt),
                None => {
                    // Не удалось разобрать — восстанавливаемся: пропускаем до конца строки
                    self.recover_to_next_line();
                }
            }
        }

        ast
    }

    // =========================================================================
    // Разбор утверждений (Statement)
    // =========================================================================

    /// Разбирает одно утверждение: метку, инструкцию или директиву.
    fn parse_statement(&mut self) -> Option<Statement> {
        let tok = self.peek();

        match tok.kind {
            // Метка: Ident ':'
            TokenKind::Ident(name_id) => {
                // Смотрим вперёд на следующий токен
                if self.peek_next_kind() == TokenKind::Colon {
                    self.advance(); // потребляем Ident
                    self.advance(); // потребляем ':'
                    // После метки обычно идёт \n или следующая инструкция на той же строке
                    self.skip_newlines();
                    return Some(Statement::Label(name_id));
                }
                // Ident без ':' — неожиданный токен
                let err_tok = self.advance();
                self.push_error(ParserErrorKind::UnexpectedToken(err_tok.kind), err_tok.pos);
                None
            }

            // Инструкция: Mnemonic [op1 [, op2 [, op3]]]
            TokenKind::Mnemonic(mnemonic) => {
                self.advance(); // потребляем мнемонику
                let operands = self.parse_operand_list();
                self.expect_end_of_line();
                Some(Statement::Instruction(Instruction { mnemonic, operands }))
            }

            // Директива: '.' Ident [operands...]
            // В нашем лексере '.' — отдельный токен, за ним идёт Ident с именем директивы.
            // Но лексер также выдаёт Ident(".text") целиком для слов типа ".global".
            // Рассмотрим оба варианта.
            TokenKind::Dot => {
                let dot_pos = tok.pos;
                self.advance(); // потребляем '.'
                self.parse_directive_after_dot(dot_pos)
            }

            TokenKind::Newline | TokenKind::End => {
                self.advance();
                None
            }

            // Всё остальное — ошибка
            _ => {
                let err_tok = self.advance();
                self.push_error(ParserErrorKind::UnexpectedToken(err_tok.kind), err_tok.pos);
                None
            }
        }
    }

    // =========================================================================
    // Разбор директив
    // =========================================================================

    /// Разбирает директиву, когда '.' уже потреблён.
    fn parse_directive_after_dot(&mut self, dot_pos: Span) -> Option<Statement> {
        // После '.' должен идти Ident с именем директивы
        let name_tok = self.peek();
        let directive_name = match name_tok.kind {
            TokenKind::Ident(id) => {
                let name = self.str_pool.get(id).to_string();
                self.advance();
                name
            }
            _ => {
                self.push_error(
                    ParserErrorKind::UnexpectedToken(name_tok.kind),
                    name_tok.pos,
                );
                return None;
            }
        };

        use std::str::FromStr;
        let kind = match DirectiveKind::from_str(&directive_name) {
            Ok(k) => k,
            Err(_) => {
                // Неизвестная директива — пропускаем строку
                self.push_error(ParserErrorKind::UnexpectedToken(TokenKind::Dot), dot_pos);
                self.recover_to_next_line();
                return None;
            }
        };

        let operands = self.parse_directive_operands(kind, dot_pos)?;
        self.expect_end_of_line();

        Some(Statement::Directive(Directive { kind, operands }))
    }

    /// Разбирает операнды директивы в зависимости от её типа.
    fn parse_directive_operands(
        &mut self,
        kind: DirectiveKind,
        pos: Span,
    ) -> Option<Vec<DirectiveOperand>> {
        match kind {
            // Секции — без операндов
            DirectiveKind::Text | DirectiveKind::Data | DirectiveKind::Bss => Some(vec![]),

            // .global / .extern — ожидают имя символа
            DirectiveKind::Global | DirectiveKind::Extern => {
                let tok = self.peek();
                match tok.kind {
                    TokenKind::Ident(id) => {
                        self.advance();
                        Some(vec![DirectiveOperand::Symbol(id)])
                    }
                    _ => {
                        self.push_error(ParserErrorKind::MissingDirectiveOperand, pos);
                        None
                    }
                }
            }

            // .byte / .word / .dword / .quad — числовое значение
            DirectiveKind::Byte
            | DirectiveKind::Word
            | DirectiveKind::Dword
            | DirectiveKind::Qword => {
                let mut operands = vec![];
                loop {
                    let tok = self.peek();
                    match tok.kind {
                        TokenKind::Integer(n) => {
                            self.advance();
                            operands.push(DirectiveOperand::Number(n));
                        }
                        TokenKind::Ident(id) => {
                            // Ссылка на символ/метку: .quad my_label
                            self.advance();
                            operands.push(DirectiveOperand::Symbol(id));
                        }
                        _ => break,
                    }
                    // Если следующий токен — запятая, продолжаем список
                    if self.peek_kind() == TokenKind::Comma {
                        self.advance();
                    } else {
                        break;
                    }
                }
                if operands.is_empty() {
                    self.push_error(ParserErrorKind::MissingDirectiveOperand, pos);
                    None
                } else {
                    Some(operands)
                }
            }

            // .ascii / .asciz — строковый литерал: .ascii "Hello, world!\n"
            DirectiveKind::Ascii => {
                let tok = self.peek();
                match tok.kind {
                    TokenKind::StringLiteral(id) => {
                        self.advance();
                        Some(vec![DirectiveOperand::StringLiteral(id)])
                    }
                    _ => {
                        self.push_error(ParserErrorKind::MissingDirectiveOperand, tok.pos);
                        None
                    }
                }
            }

            // .align — числовое значение (степень двойки)
            DirectiveKind::Align => {
                let tok = self.peek();
                match tok.kind {
                    TokenKind::Integer(n) => {
                        self.advance();
                        Some(vec![DirectiveOperand::Number(n)])
                    }
                    _ => {
                        self.push_error(ParserErrorKind::MissingDirectiveOperand, pos);
                        None
                    }
                }
            }
        }
    }

    // =========================================================================
    // Разбор операндов инструкций
    // =========================================================================

    /// Разбирает список операндов инструкции: `op1`, `op1, op2`, `op1, op2, op3`
    fn parse_operand_list(&mut self) -> Vec<Operand> {
        let mut operands = vec![];

        // Инструкции без операндов
        if self.is_end_of_line() {
            return operands;
        }

        // Первый операнд
        match self.parse_operand() {
            Some(op) => operands.push(op),
            None => return operands,
        }

        // Второй и третий операнды (через запятую)
        while self.peek_kind() == TokenKind::Comma {
            self.advance(); // потребляем ','
            match self.parse_operand() {
                Some(op) => operands.push(op),
                None => break,
            }
        }

        operands
    }

    /// Разбирает один операнд инструкции.
    ///
    /// `operand_index` — порядковый номер этого операнда (0 = первый, 1 = второй).
    /// Используется для определения, является ли операнд "меткой" (jmp/call всегда
    /// имеют метку как единственный операнд).
    fn parse_operand(&mut self) -> Option<Operand> {
        let tok = self.peek();

        match tok.kind {
            // Регистр
            TokenKind::Register(reg) => {
                self.advance();
                Some(Operand::Register(reg))
            }

            // Непосредственное число
            TokenKind::Integer(n) => {
                self.advance();
                Some(Operand::Immediate(n))
            }

            // Тип данных: `qword ptr [...]` или просто `qword [...]`
            TokenKind::Type(_data_type) => {
                self.advance(); // потребляем тип
                // Пропускаем необязательное 'ptr' (оно токенизируется как Ident("ptr"))
                if let TokenKind::Ident(id) = self.peek_kind() {
                    let word = self.str_pool.get(id).to_lowercase();
                    if word == "ptr" {
                        self.advance();
                    }
                }
                // После типа обязательно идёт `[`
                if self.peek_kind() == TokenKind::OpeningSquareBracket {
                    self.advance();
                    self.parse_memory_operand(tok.pos)
                } else {
                    self.push_error(ParserErrorKind::UnexpectedToken(self.peek().kind), tok.pos);
                    None
                }
            }

            // Открывающая скобка: `[rax + ...]`
            TokenKind::OpeningSquareBracket => {
                self.advance();
                self.parse_memory_operand(tok.pos)
            }

            // Идентификатор (метка): `jmp my_label`, `call _start`
            TokenKind::Ident(id) => {
                self.advance();
                Some(Operand::Label(id))
            }

            // Знак минуса перед числом: `mov rax, -1`
            TokenKind::Minus => {
                self.advance();
                let num_tok = self.peek();
                if let TokenKind::Integer(n) = num_tok.kind {
                    self.advance();
                    Some(Operand::Immediate(-n))
                } else {
                    self.push_error(
                        ParserErrorKind::UnexpectedOperand(num_tok.kind),
                        num_tok.pos,
                    );
                    None
                }
            }

            _ => {
                self.push_error(ParserErrorKind::UnexpectedOperand(tok.kind), tok.pos);
                None
            }
        }
    }

    // =========================================================================
    // Разбор адресации памяти [base + index * scale + displacement]
    // =========================================================================

    /// Разбирает содержимое `[...]`, когда `[` уже потреблён.
    ///
    /// Грамматика (в упрощённой форме):
    /// ```text
    /// mem  ::= '[' expr ']'
    /// expr ::= term ('+' term | '-' term)*
    /// term ::= reg ('*' scale)?
    ///        | integer
    /// ```
    fn parse_memory_operand(&mut self, open_bracket_pos: Span) -> Option<Operand> {
        let mut base: Option<Registers> = None;
        let mut index: Option<GPRs> = None;
        let mut scale: Option<Scale> = None;
        let mut displacement: i32 = 0;

        // Знак для следующего терма: +1 или -1
        let mut sign: i32 = 1;

        loop {
            let tok = self.peek();

            match tok.kind {
                // Конец выражения
                TokenKind::EndingSquareBracket => {
                    self.advance();
                    break;
                }

                // End файла без закрывающей скобки — ошибка
                TokenKind::End | TokenKind::Newline => {
                    self.push_error(ParserErrorKind::UnclosedMemoryBracket, open_bracket_pos);
                    return None;
                }

                // Знаки: '+' и '-'
                TokenKind::Plus => {
                    self.advance();
                    sign = 1;
                    continue;
                }
                TokenKind::Minus => {
                    self.advance();
                    sign = -1;
                    continue;
                }

                // Регистр
                TokenKind::Register(reg) => {
                    self.advance();

                    // Смотрим вперёд: если следующий токен '*' — это index * scale
                    if self.peek_kind() == TokenKind::Asterisk {
                        self.advance(); // потребляем '*'
                        let scale_tok = self.peek();
                        if let TokenKind::Integer(n) = scale_tok.kind {
                            self.advance();
                            let s = match n {
                                1 => Scale::One,
                                2 => Scale::Two,
                                4 => Scale::Four,
                                8 => Scale::Eight,
                                _ => {
                                    self.push_error(
                                        ParserErrorKind::InvalidScale(n),
                                        scale_tok.pos,
                                    );
                                    return None;
                                }
                            };
                            // Индексный регистр должен быть GPR
                            match reg {
                                Registers::GPR(gpr) => {
                                    index = Some(gpr);
                                    scale = Some(s);
                                }
                                _ => {
                                    self.push_error(
                                        ParserErrorKind::UnexpectedOperand(TokenKind::Register(
                                            reg,
                                        )),
                                        tok.pos,
                                    );
                                    return None;
                                }
                            }
                        } else {
                            self.push_error(
                                ParserErrorKind::UnexpectedToken(scale_tok.kind),
                                scale_tok.pos,
                            );
                            return None;
                        }
                    } else {
                        // Это базовый регистр
                        base = Some(reg);
                    }
                }

                // Числовое смещение
                TokenKind::Integer(n) => {
                    self.advance();
                    let signed = (n) * (sign as i64);
                    if signed > i32::MAX as i64 || signed < i32::MIN as i64 {
                        self.push_error(ParserErrorKind::DisplacementOverflow(signed), tok.pos);
                        return None;
                    }
                    displacement = displacement.wrapping_add(signed as i32);
                    sign = 1; // сбрасываем знак
                }

                // Неожиданный токен внутри []
                _ => {
                    self.push_error(ParserErrorKind::UnexpectedToken(tok.kind), tok.pos);
                    return None;
                }
            }
        }

        Some(Operand::Memory(MemoryAddress {
            base,
            index,
            scale,
            displacement,
        }))
    }

    // =========================================================================
    // Вспомогательные методы навигации по токенам
    // =========================================================================

    /// Возвращает текущий токен без продвижения курсора.
    #[inline]
    fn peek(&self) -> Token {
        // Безопасно: у нас всегда есть минимум токен `End` в конце
        self.tokens[self.cursor.min(self.tokens.len() - 1)]
    }

    /// Возвращает `TokenKind` текущего токена.
    #[inline]
    fn peek_kind(&self) -> TokenKind {
        self.peek().kind
    }

    /// Заглядывает на токен вперёд (cursor + 1), не продвигая курсор.
    #[inline]
    fn peek_next_kind(&self) -> TokenKind {
        let next = (self.cursor + 1).min(self.tokens.len() - 1);
        self.tokens[next].kind
    }

    /// Потребляет текущий токен и возвращает его, продвигая курсор.
    #[inline]
    fn advance(&mut self) -> Token {
        let tok = self.peek();
        if self.cursor < self.tokens.len() - 1 {
            self.cursor += 1;
        }
        tok
    }

    /// Пропускает все токены `Newline`.
    fn skip_newlines(&mut self) {
        while self.peek_kind() == TokenKind::Newline {
            self.advance();
        }
    }

    /// Проверяет, что мы находимся в конце логической строки.
    #[inline]
    fn is_end_of_line(&self) -> bool {
        matches!(self.peek_kind(), TokenKind::Newline | TokenKind::End)
    }

    /// Ожидает конец строки (`Newline` или `End`).
    /// Потребляет `Newline`, если он есть.
    fn expect_end_of_line(&mut self) {
        match self.peek_kind() {
            TokenKind::Newline => {
                self.advance();
            }
            TokenKind::End => {}
            tok => {
                let pos = self.peek().pos;
                self.push_error(
                    ParserErrorKind::ExpectedTokenButFound {
                        expected: TokenKind::Newline,
                        got: tok,
                    },
                    pos,
                );
                self.recover_to_next_line();
            }
        }
    }

    /// Восстановление после ошибки: пропускаем токены до `Newline` или `End`.
    fn recover_to_next_line(&mut self) {
        while !matches!(self.peek_kind(), TokenKind::Newline | TokenKind::End) {
            self.advance();
        }
        if self.peek_kind() == TokenKind::Newline {
            self.advance();
        }
    }

    /// Добавляет ошибку в список.
    fn push_error(&mut self, kind: ParserErrorKind, pos: Span) {
        self.errors.push(ParserError::new(kind, pos));
    }
}
