use crate::prelude::*;

impl Runtime {
    pub fn parse_claim_stmt(&mut self, tb: &mut TokenBlock) -> Result<Stmt, RuntimeError> {
        tb.skip_token(CLAIM)?;
        Ok(self.parse_multiline_fact_claim(tb)?.into())
    }

    fn parse_multiline_fact_claim(
        &mut self,
        tb: &mut TokenBlock,
    ) -> Result<ClaimStmt, RuntimeError> {
        tb.skip_token(COLON)?;
        if tb.body.is_empty() {
            return Err(RuntimeError::new_parse_error_with_msg_position_previous_error(
                "claim : expects at least one body block (=>: fact)".to_string(),
                tb.line_file.clone(),
                None,
            ));
        }
        let fact = {
            let first = tb.body.get_mut(0).ok_or_else(|| {
                RuntimeError::new_parse_error_with_msg_position_previous_error(
                    "claim : expects at least one body block (=>: fact)".to_string(),
                    tb.line_file.clone(),
                    None,
                )
            })?;

            first.skip_token(PROVE)?;
            first.skip_token(COLON)?;

            let body_block = first.body.get_mut(0).ok_or_else(|| {
                RuntimeError::new_parse_error_with_msg_position_previous_error(
                    "claim =>: expects exactly one body block (the fact)".to_string(),
                    first.line_file.clone(),
                    None,
                )
            })?;
            let f = self.parse_fact(body_block)?;
            if matches!(&f, Fact::ForallFactWithIff(_)) {
                return Err(RuntimeError::new_parse_error_with_msg_position_previous_error(
                    "claim multiline fact cannot be iff".to_string(),
                    first.line_file.clone(),
                    None,
                ));
            }
            Ok::<Fact, RuntimeError>(f)
        }?;

        let proof: Vec<Stmt> = tb
            .body
            .iter_mut()
            .skip(1)
            .map(|b| self.parse_stmt(b))
            .collect::<Result<_, _>>()?;
        Ok(ClaimStmt::new(fact, proof, tb.line_file.clone()))
    }
}
