//! Tools that enable llms to ask questions to users. They are based on the `Question` struct
//! that we use to create surveys.
//!
//! Core tools:
//! - `Question` - Ask a question to the user
//!
//! Question types:
//! - `Question::ask` - Ask a simple text question to the user
//! - `Question::confirm` - Ask a confirmation question to the user
//! - `Question::select` - Ask a multiple choice question to the user

use crate::question_and_answers::{Question, QuestionType};
use anyhow::Result;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use super::TypedTool;

#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct SingleQuestion {
    question: String,
    #[serde(default)]
    help_message: Option<String>,
    #[serde(default)]
    options: Option<Vec<String>>,
    #[serde(default)]
    is_confirmation: bool,
}

#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct QuestionsArgs {
    questions: Vec<SingleQuestion>,
}

#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct QuestionsOutput {
    answers: Vec<String>,
}

pub struct QuestionsTool;

impl TypedTool for QuestionsTool {
    type Args = QuestionsArgs;
    type Output = QuestionsOutput;

    fn name(&self) -> &str {
        "ask-questions"
    }

    fn description(&self) -> &str {
        "Ask the user multiple questions. Each question can be a text question, multiple choice, or confirmation. Use the continuation-tool to continue the conversation after the questions are answered."
    }

    fn execute(&self, args: Self::Args) -> Result<Self::Output> {
        let mut answers = Vec::new();

        for q in args.questions {
            let question = if q.is_confirmation {
                Question::confirm(&q.question)
            } else if let Some(options) = q.options {
                Question::select(&q.question, options)
            } else {
                Question::ask(&q.question)
            };

            let answer = if let Some(help) = q.help_message {
                question.with_help(help).get_answer()?
            } else {
                question.get_answer()?
            };

            answers.push(answer);
        }

        Ok(QuestionsOutput { answers })
    }
}
