use crate::lst_parser::{
    error::SyntaxError, grammar::expression::atom, CompletedMarker, Marker, Parser, SyntaxKind::*,
};

pub fn vec_matrix_list(p: &mut Parser) -> CompletedMarker {
    let start = p.start("vec_matrix_list_start");
    assert!(p.eat(L_BRACK));
    let row_start = p.start("matrix_row_start");
    if let Some(item) = atom(p) {
        item.precede(p, "coll_item_start")
            .complete(p, COLLECTION_ITEM);

        if p.at(COMMA) {
            row_start.abandon(p);
            return finish_list(p, start);
        }

        finish_mat_or_vec(p, start, row_start)
    } else if p.eat(R_BRACK) {
        row_start.abandon(p);
        start.complete(p, LIST)
    } else {
        row_start.abandon(p);
        start.error(p, SyntaxError::Expected(vec![EXPR, R_BRACK]))
    }
}

fn finish_list(p: &mut Parser, list_start: Marker) -> CompletedMarker {
    loop {
        if p.eat(COMMA) {
            if let Some(item) = atom(p) {
                item.precede(p, "coll_item_start")
                    .complete(p, COLLECTION_ITEM);
            } else if p.eat(R_BRACK) {
                return list_start.complete(p, LIST);
            }
        } else if p.eat(R_BRACK) {
            return list_start.complete(p, LIST);
        } else if let Some(item) = atom(p) {
            item.precede(p, "next_item")
                .complete(p, COLLECTION_ITEM)
                .precede(p, "err_space_sep")
                .error(p, SyntaxError::SpaceSepInList);
        } else if p.at(SEMICOLON) {
            let semi_err = p.start("semicolon_err");
            p.eat(SEMICOLON);
            semi_err.error(p, SyntaxError::SemicolonInList);
            if let Some(item) = atom(p) {
                item.precede(p, "coll_item_start")
                    .complete(p, COLLECTION_ITEM);
            } else if p.eat(R_BRACK) {
                return list_start.complete(p, LIST);
            }
        }
    }
}

// TODO: handle commas, general other wrong toks
fn finish_mat_or_vec(p: &mut Parser, coll_start: Marker, mut row_start: Marker) -> CompletedMarker {
    let mut is_matrix = false;
    let mut row_item_count = 1;
    loop {
        if let Some(item) = atom(p) {
            item.precede(p, "coll_item_start")
                .complete(p, COLLECTION_ITEM);
            row_item_count += 1;
        } else if p.at(SEMICOLON) {
            is_matrix = true;
            row_start.complete(p, MAT_ROW);
            p.eat(SEMICOLON);
            row_start = p.start("matrix_row_start");
            row_item_count = 0;
        } else if p.at(R_BRACK) {
            if is_matrix && row_item_count == 0 {
                row_start.abandon(p);
                p.eat(R_BRACK);
                return coll_start.complete(p, MATRIX);
            } else if is_matrix {
                row_start.complete(p, MAT_ROW);
                p.eat(R_BRACK);
                return coll_start.complete(p, MATRIX);
            } else {
                row_start.abandon(p);
                p.eat(R_BRACK);
                return coll_start.complete(p, VEC);
            }
        } else if p.at(COMMA) {
            let err_unexpected_comma = p.start("err_unexpected_comma");
            p.do_bump();
            err_unexpected_comma.error(p, SyntaxError::CommaInMatOrVec);
        } else {
            let err_unexpected = p.start("err_unexpected_tok");
            p.do_bump();
            err_unexpected.error(p, SyntaxError::Expected(vec![EXPR, SEMICOLON, R_BRACK]));
        }
    }
}
