use std::ops::Range;

use crate::{
    ParseError, Parser,
    ast::{Expr, Ident, Path},
    lexer::Token,
};

#[derive(Debug)]
pub struct DeleteFromStmt<'a> {
    pub span: Range<usize>,
    pub table: Path<'a>,
    pub alias: Option<Ident<'a>>,
    pub selection: Option<Expr<'a>>,
}

impl<'a> Parser<'a> {
    pub(crate) fn parse_delete_stmt(&mut self) -> Result<DeleteFromStmt<'a>, ParseError> {
        self.consume(&[Token::Delete])?;
        self.consume(&[Token::From])?;
        let table = self.parse_path()?;

        let alias = if self.lexer.peek().token == Token::As {
            self.lexer.advance();
            Some(self.parse_ident()?)
        } else {
            None
        };

        let selection = if self.lexer.peek().token == Token::Where {
            self.lexer.advance();
            Some(self.parse_expr()?)
        } else {
            None
        };

        self.consume(&[Token::Semicolon])?;

        Ok(DeleteFromStmt {
            span: self.current_span.clone(),
            table,
            alias,
            selection,
        })
    }
}

#[cfg(test)]
mod tests {
    use crate::{ast::*, parse, tests::assert_no_errors};

    #[test]
    fn test_delete_all() {
        let source = "delete from mydb.users;";
        let (stmts, errors) = parse(source);
        assert_no_errors(&errors);
        let Stmt::DeleteFrom(stmt) = &stmts[0] else {
            panic!("expected delete")
        };
        assert!(matches!(stmt.selection, None));
    }
}
