use crate::{
    llms::communication::email::{send_email, Email},
    question_and_answers::Question,
    survey::utils::AppSpinner,
};
use anyhow::Result;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use super::TypedTool;

#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct EmailArgs {
    to: Vec<String>,
    subject: String,
    body: String,
    #[serde(default)]
    cc: Option<Vec<String>>,
    #[serde(default)]
    bcc: Option<Vec<String>>,
}

#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct EmailOutput {
    success: bool,
    message: String,
}

pub struct EmailTool;

impl TypedTool for EmailTool {
    type Args = EmailArgs;
    type Output = EmailOutput;

    fn name(&self) -> &str {
        "send-email"
    }

    fn description(&self) -> &str {
        "A tool to send an email to recipients. Use this tool when a user wants you to send an email."
    }

    fn execute(&self, args: Self::Args) -> Result<Self::Output> {
        let to_refs: Vec<&str> = args.to.iter().map(|s| s.as_str()).collect();
        let cc_refs: Vec<&str> = args
            .cc
            .as_ref()
            .map_or(vec![], |cc| cc.iter().map(|s| s.as_str()).collect());
        let bcc_refs: Vec<&str> = args
            .bcc
            .as_ref()
            .map_or(vec![], |bcc| bcc.iter().map(|s| s.as_str()).collect());

        let email = Email::new("aurora@514.ai", &args.subject, to_refs, &args.body)
            .with_cc(cc_refs)
            .with_bcc(bcc_refs);

        Question::confirm(format!(
            "Proceed to send an email to: {}",
            email.get_to().join(", ")
        ))
        .with_help(email.get_body().ok_or(anyhow::anyhow!("No body found"))?)
        .get_answer()?;

        let mut spinner = AppSpinner::new("Sending email...");
        match send_email(&email) {
            Ok(_) => {
                spinner.stop_with_success_message(&format!(
                    "Email sent successfully to: {}",
                    email.get_to().join(", ")
                ));
                Ok(EmailOutput {
                    success: true,
                    message: "Email sent successfully".to_string(),
                })
            }
            Err(e) => {
                spinner.stop_with_error_message(&format!("Failed to send email: {}", e));
                Ok(EmailOutput {
                    success: false,
                    message: format!("Failed to send email: {}", e),
                })
            }
        }
    }
}
