#![allow(unused_imports)]
use super::*;
use std::sync::{Arc, Mutex};

type SentEmailRecord = (String, String, String, String);
type SentEmailSink = Arc<Mutex<Vec<SentEmailRecord>>>;

/// Mock email provider for testing.
struct MockEmailProvider {
    sent: SentEmailSink,
}

impl MockEmailProvider {
    fn new() -> (Self, SentEmailSink) {
        let sent = Arc::new(Mutex::new(Vec::new()));
        (Self { sent: sent.clone() }, sent)
    }
}

#[async_trait]
impl EmailProvider for MockEmailProvider {
    async fn send(&self, to: &str, subject: &str, html: &str, text: &str) -> AuthResult<()> {
        self.sent.lock().unwrap().push((
            to.to_string(),
            subject.to_string(),
            html.to_string(),
            text.to_string(),
        ));
        Ok(())
    }
}

#[tokio::test]
async fn test_console_email_provider_send() {
    let provider = ConsoleEmailProvider;
    let result = provider
        .send("user@example.com", "Test Subject", "<h1>Hi</h1>", "Hi")
        .await;
    assert!(result.is_ok());
}

#[tokio::test]
async fn test_mock_email_provider_records_sends() {
    let (provider, sent) = MockEmailProvider::new();
    provider
        .send("a@b.com", "Sub", "<p>html</p>", "text")
        .await
        .unwrap();
    provider.send("c@d.com", "Sub2", "", "text2").await.unwrap();

    let messages = sent.lock().unwrap();
    assert_eq!(messages.len(), 2);
    assert_eq!(messages[0].0, "a@b.com");
    assert_eq!(messages[1].0, "c@d.com");
}

#[tokio::test]
async fn test_trait_object_works() {
    let provider: Box<dyn EmailProvider> = Box::new(ConsoleEmailProvider);
    let result = provider.send("user@example.com", "Test", "", "body").await;
    assert!(result.is_ok());
}

#[tokio::test]
async fn test_missing_provider_returns_error() {
    use crate::adapters::MemoryDatabaseAdapter;
    use crate::config::AuthConfig;
    use crate::plugin::AuthContext;

    let config = Arc::new(AuthConfig::new("test-secret-key-at-least-32-chars-long"));
    let database = Arc::new(MemoryDatabaseAdapter::new());
    let ctx = AuthContext::new(config, database);

    let result = ctx.email_provider();
    assert!(result.is_err());
}
