package org.jcnc.snow.compiler.lexer.core;

import org.jcnc.snow.compiler.lexer.base.TokenScanner;
import org.jcnc.snow.compiler.lexer.scanners.*;
import org.jcnc.snow.compiler.lexer.token.Token;

import java.util.ArrayList;
import java.util.List;

/**
 * {@code LexerEngine} 是编译器前端的词法分析器核心实现。
 * <p>
 * 它负责将源代码字符串按顺序扫描并转换为一系列 {@link Token} 实例，
 * 每个 Token 表示语法上可识别的最小单位（如标识符、关键字、常量、运算符等）。
 * <p>
 * 分析流程通过注册多个 {@link TokenScanner} 扫描器实现类型识别，
 * 并由 {@link LexerContext} 提供字符流与位置信息支持。
 * </p>
 */
public class LexerEngine {

    /** 扫描生成的 Token 序列（含 EOF） */
    private final List<Token> tokens = new ArrayList<>();

    /** 词法上下文，提供字符流读取与位置信息 */
    private final LexerContext context;

    /** Token 扫描器集合，按优先级顺序组织，用于识别不同类别的 Token */
    private final List<TokenScanner> scanners;

    /**
     * 构造一个 {@code LexerEngine} 实例，并初始化内部扫描器与上下文。
     * 调用构造函数时即开始词法扫描，生成完整 Token 序列。
     *
     * @param source 原始源代码文本
     */
    public LexerEngine(String source) {
        this.context = new LexerContext(source);

        // 按优先级注册所有支持的 Token 扫描器
        this.scanners = List.of(
                new WhitespaceTokenScanner(), // 跳过空格、制表符等
                new NewlineTokenScanner(),    // 处理换行符，生成 NEWLINE Token
                new CommentTokenScanner(),    // 处理单行/多行注释
                new NumberTokenScanner(),     // 识别整数与浮点数
                new IdentifierTokenScanner(), // 识别标识符与关键字
                new StringTokenScanner(),     // 处理字符串常量
                new OperatorTokenScanner(),   // 处理运算符
                new SymbolTokenScanner(),     // 处理括号、分号等符号
                new UnknownTokenScanner()     // 捕捉无法识别的字符
        );

        scanAllTokens();
    }

    /**
     * 执行主扫描流程，将整个源代码转换为 Token 序列。
     * <p>
     * 每次扫描尝试依次使用各个 {@link TokenScanner}，直到某一扫描器能够处理当前字符。
     * 若无匹配扫描器，交由 {@code UnknownTokenScanner} 处理。
     * 扫描结束后自动附加一个 EOF（文件结束）Token。
     * </p>
     */
    private void scanAllTokens() {
        while (!context.isAtEnd()) {
            char currentChar = context.peek();

            for (TokenScanner scanner : scanners) {
                if (scanner.canHandle(currentChar, context)) {
                    scanner.handle(context, tokens);
                    break;
                }
            }
        }

        tokens.add(Token.eof(context.getLine()));
    }

    /**
     * 返回词法分析生成的所有 Token（含 EOF）。
     *
     * @return Token 的不可变副本列表
     */
    public List<Token> getAllTokens() {
        return List.copyOf(tokens);
    }
}