//! Email handler functions
//!
//! This module implements the actual handler functions for email-related HTTP endpoints.
//! It includes handlers for contact forms, support forms, custom emails, and notifications.

use crate::email::{EmailService, FormSubmission};
use crate::handlers::email::{
    EmailErrorResponse, EmailSuccessResponse, check_rate_limit, extract_ip_address,
    extract_language_from_headers, extract_user_agent, validate_form_submission,
    validate_required_field,
};
use axum::{
    extract::{ConnectInfo, State},
    http::{HeaderMap, StatusCode},
    response::Json,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use tracing::{debug, error, info, warn};

/// Contact form request structure
#[derive(Debug, Deserialize)]
pub struct ContactFormRequest {
    pub name: String,
    pub email: String,
    pub subject: String,
    pub message: String,
    pub recipient: Option<String>,
}

/// Support form request structure
#[derive(Debug, Deserialize)]
pub struct SupportFormRequest {
    pub name: String,
    pub email: String,
    pub subject: String,
    pub message: String,
    pub priority: Option<String>,
    pub category: Option<String>,
    pub recipient: Option<String>,
}

/// Custom email request structure
#[derive(Debug, Deserialize)]
pub struct CustomEmailRequest {
    pub to: String,
    pub to_name: Option<String>,
    pub subject: String,
    pub text_body: Option<String>,
    pub html_body: Option<String>,
    pub template: Option<String>,
    pub template_data: Option<HashMap<String, serde_json::Value>>,
    pub cc: Option<Vec<String>>,
    pub bcc: Option<Vec<String>>,
    pub reply_to: Option<String>,
}

/// Notification request structure
#[derive(Debug, Deserialize)]
pub struct NotificationRequest {
    pub to: String,
    pub title: String,
    pub message: String,
    pub content: Option<String>,
}

/// Email status response
#[derive(Debug, Serialize)]
pub struct EmailStatusResponse {
    pub enabled: bool,
    pub provider: String,
    pub configured: bool,
    pub templates: Vec<String>,
    pub languages: Option<Vec<String>>,
}

/// Handle contact form submission
pub async fn send_contact_form(
    State(email_service): State<Arc<EmailService>>,
    ConnectInfo(addr): ConnectInfo<SocketAddr>,
    headers: HeaderMap,
    Json(request): Json<ContactFormRequest>,
) -> Result<Json<EmailSuccessResponse>, (StatusCode, Json<EmailErrorResponse>)> {
    debug!("Received contact form submission from: {}", addr.ip());

    // Extract request metadata
    let ip_address = extract_ip_address(&headers, Some(ConnectInfo(addr)));
    let user_agent = extract_user_agent(&headers);
    let language = extract_language_from_headers(&headers);

    // Check rate limiting
    if let Some(ip) = &ip_address {
        if !check_rate_limit(ip) {
            warn!("Rate limit exceeded for IP: {}", ip);
            return Err((
                StatusCode::TOO_MANY_REQUESTS,
                Json(EmailErrorResponse::new(
                    "Rate Limit Exceeded",
                    "Too many requests from this IP address",
                    "RATE_LIMIT_EXCEEDED",
                )),
            ));
        }
    }

    // Validate the form data
    if let Err(validation_error) = validate_form_submission(
        &request.name,
        &request.email,
        &request.subject,
        &request.message,
    ) {
        return Err((
            StatusCode::BAD_REQUEST,
            Json(EmailErrorResponse::validation_error(&validation_error)),
        ));
    }

    // Create form submission
    let mut submission = FormSubmission::new(
        "contact",
        &request.name,
        &request.email,
        &request.subject,
        &request.message,
    );

    // Add metadata
    if let Some(ip) = ip_address {
        submission = submission.ip_address(&ip);
    }
    if let Some(ua) = user_agent {
        submission = submission.user_agent(&ua);
    }

    // Determine recipient
    let recipient = request
        .recipient
        .as_ref()
        .unwrap_or(&email_service.get_config().default_from);

    // Send the email with detected language
    match email_service
        .send_form_submission_with_language(&submission, recipient, &language)
        .await
    {
        Ok(message_id) => {
            info!(
                "Contact form submitted successfully: {} -> {}",
                request.email, recipient
            );
            Ok(Json(EmailSuccessResponse::new(
                "Contact form submitted successfully",
                &message_id,
                "sent",
            )))
        }
        Err(e) => {
            error!("Failed to send contact form: {}", e);
            Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(EmailErrorResponse::email_error(&format!(
                    "Failed to send contact form: {}",
                    e
                ))),
            ))
        }
    }
}

/// Handle support form submission
pub async fn send_support_form(
    State(email_service): State<Arc<EmailService>>,
    ConnectInfo(addr): ConnectInfo<SocketAddr>,
    headers: HeaderMap,
    Json(request): Json<SupportFormRequest>,
) -> Result<Json<EmailSuccessResponse>, (StatusCode, Json<EmailErrorResponse>)> {
    debug!("Received support form submission from: {}", addr.ip());

    // Extract request metadata
    let ip_address = extract_ip_address(&headers, Some(ConnectInfo(addr)));
    let user_agent = extract_user_agent(&headers);
    let language = extract_language_from_headers(&headers);

    // Check rate limiting
    if let Some(ip) = &ip_address {
        if !check_rate_limit(ip) {
            warn!("Rate limit exceeded for IP: {}", ip);
            return Err((
                StatusCode::TOO_MANY_REQUESTS,
                Json(EmailErrorResponse::new(
                    "Rate Limit Exceeded",
                    "Too many requests from this IP address",
                    "RATE_LIMIT_EXCEEDED",
                )),
            ));
        }
    }

    // Validate the form data
    if let Err(validation_error) = validate_form_submission(
        &request.name,
        &request.email,
        &request.subject,
        &request.message,
    ) {
        return Err((
            StatusCode::BAD_REQUEST,
            Json(EmailErrorResponse::validation_error(&validation_error)),
        ));
    }

    // Validate priority if provided
    if let Some(priority) = &request.priority {
        if !["low", "normal", "high", "urgent"].contains(&priority.to_lowercase().as_str()) {
            return Err((
                StatusCode::BAD_REQUEST,
                Json(EmailErrorResponse::validation_error(
                    "Priority must be one of: low, normal, high, urgent",
                )),
            ));
        }
    }

    // Determine recipient
    let recipient = request
        .recipient
        .as_ref()
        .unwrap_or(&email_service.get_config().default_from);

    // Send the support form with detected language
    match email_service
        .send_support_form_with_language(
            &request.name,
            &request.email,
            &request.subject,
            &request.message,
            request.priority.as_deref(),
            request.category.as_deref(),
            recipient,
            &language,
        )
        .await
    {
        Ok(message_id) => {
            info!(
                "Support form submitted successfully: {} -> {}",
                request.email, recipient
            );
            Ok(Json(EmailSuccessResponse::new(
                "Support form submitted successfully",
                &message_id,
                "sent",
            )))
        }
        Err(e) => {
            error!("Failed to send support form: {}", e);
            Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(EmailErrorResponse::email_error(&format!(
                    "Failed to send support form: {}",
                    e
                ))),
            ))
        }
    }
}

/// Handle custom email sending
pub async fn send_custom_email(
    State(email_service): State<Arc<EmailService>>,
    ConnectInfo(addr): ConnectInfo<SocketAddr>,
    headers: HeaderMap,
    Json(request): Json<CustomEmailRequest>,
) -> Result<Json<EmailSuccessResponse>, (StatusCode, Json<EmailErrorResponse>)> {
    debug!("Received custom email request from: {}", addr.ip());

    // Extract request metadata
    let ip_address = extract_ip_address(&headers, Some(ConnectInfo(addr)));
    let language = extract_language_from_headers(&headers);

    // Check rate limiting
    if let Some(ip) = &ip_address {
        if !check_rate_limit(ip) {
            warn!("Rate limit exceeded for IP: {}", ip);
            return Err((
                StatusCode::TOO_MANY_REQUESTS,
                Json(EmailErrorResponse::new(
                    "Rate Limit Exceeded",
                    "Too many requests from this IP address",
                    "RATE_LIMIT_EXCEEDED",
                )),
            ));
        }
    }

    // Validate required fields
    if let Err(validation_error) = validate_required_field(&request.to, "Recipient") {
        return Err((
            StatusCode::BAD_REQUEST,
            Json(EmailErrorResponse::validation_error(&validation_error)),
        ));
    }

    if let Err(validation_error) = validate_required_field(&request.subject, "Subject") {
        return Err((
            StatusCode::BAD_REQUEST,
            Json(EmailErrorResponse::validation_error(&validation_error)),
        ));
    }

    // Validate that we have either a body or template
    if request.text_body.is_none() && request.html_body.is_none() && request.template.is_none() {
        return Err((
            StatusCode::BAD_REQUEST,
            Json(EmailErrorResponse::validation_error(
                "Email must have either text body, HTML body, or template",
            )),
        ));
    }

    // Build email message
    let mut email_message = crate::email::EmailMessage::new(&request.to, &request.subject);

    if let Some(to_name) = &request.to_name {
        email_message = email_message.to_name(to_name);
    }

    if let Some(text_body) = &request.text_body {
        email_message = email_message.text_body(text_body);
    }

    if let Some(html_body) = &request.html_body {
        email_message = email_message.html_body(html_body);
    }

    if let Some(template) = &request.template {
        email_message = email_message.template(template).language(&language);
        if let Some(template_data) = &request.template_data {
            email_message = email_message.template_data_map(template_data.clone());
        }
    }

    if let Some(cc_list) = &request.cc {
        for cc in cc_list {
            email_message = email_message.cc(cc);
        }
    }

    if let Some(bcc_list) = &request.bcc {
        for bcc in bcc_list {
            email_message = email_message.bcc(bcc);
        }
    }

    if let Some(reply_to) = &request.reply_to {
        email_message = email_message.reply_to(reply_to);
    }

    // Send the email with detected language
    match email_service
        .send_email_with_language(&email_message, &language)
        .await
    {
        Ok(message_id) => {
            info!("Custom email sent successfully to: {}", request.to);
            Ok(Json(EmailSuccessResponse::new(
                "Email sent successfully",
                &message_id,
                "sent",
            )))
        }
        Err(e) => {
            error!("Failed to send custom email: {}", e);
            Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(EmailErrorResponse::email_error(&format!(
                    "Failed to send email: {}",
                    e
                ))),
            ))
        }
    }
}

/// Handle notification sending
pub async fn send_notification(
    State(email_service): State<Arc<EmailService>>,
    ConnectInfo(addr): ConnectInfo<SocketAddr>,
    headers: HeaderMap,
    Json(request): Json<NotificationRequest>,
) -> Result<Json<EmailSuccessResponse>, (StatusCode, Json<EmailErrorResponse>)> {
    debug!("Received notification request from: {}", addr.ip());

    // Extract request metadata
    let ip_address = extract_ip_address(&headers, Some(ConnectInfo(addr)));
    let language = extract_language_from_headers(&headers);

    // Check rate limiting
    if let Some(ip) = &ip_address {
        if !check_rate_limit(ip) {
            warn!("Rate limit exceeded for IP: {}", ip);
            return Err((
                StatusCode::TOO_MANY_REQUESTS,
                Json(EmailErrorResponse::new(
                    "Rate Limit Exceeded",
                    "Too many requests from this IP address",
                    "RATE_LIMIT_EXCEEDED",
                )),
            ));
        }
    }

    // Validate required fields
    if let Err(validation_error) = validate_required_field(&request.to, "Recipient") {
        return Err((
            StatusCode::BAD_REQUEST,
            Json(EmailErrorResponse::validation_error(&validation_error)),
        ));
    }

    if let Err(validation_error) = validate_required_field(&request.title, "Title") {
        return Err((
            StatusCode::BAD_REQUEST,
            Json(EmailErrorResponse::validation_error(&validation_error)),
        ));
    }

    if let Err(validation_error) = validate_required_field(&request.message, "Message") {
        return Err((
            StatusCode::BAD_REQUEST,
            Json(EmailErrorResponse::validation_error(&validation_error)),
        ));
    }

    // Send the notification with detected language
    match email_service
        .send_notification_with_language(
            &request.to,
            &request.title,
            &request.message,
            request.content.as_deref(),
            &language,
        )
        .await
    {
        Ok(message_id) => {
            info!("Notification sent successfully to: {}", request.to);
            Ok(Json(EmailSuccessResponse::new(
                "Notification sent successfully",
                &message_id,
                "sent",
            )))
        }
        Err(e) => {
            error!("Failed to send notification: {}", e);
            Err((
                StatusCode::INTERNAL_SERVER_ERROR,
                Json(EmailErrorResponse::email_error(&format!(
                    "Failed to send notification: {}",
                    e
                ))),
            ))
        }
    }
}

/// Get email service status
pub async fn get_email_status(
    State(email_service): State<Arc<EmailService>>,
) -> Result<Json<EmailStatusResponse>, (StatusCode, Json<EmailErrorResponse>)> {
    debug!("Received email status request");

    let templates = email_service.get_template_names().await;
    let languages = email_service.get_available_languages().await;

    Ok(Json(EmailStatusResponse {
        enabled: email_service.is_enabled(),
        provider: email_service.provider_name().to_string(),
        configured: email_service.is_configured(),
        templates,
        languages: Some(languages),
    }))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_contact_form_request_deserialization() {
        let json = r#"
        {
            "name": "John Doe",
            "email": "john@example.com",
            "subject": "Test Subject",
            "message": "Test message",
            "recipient": "admin@example.com"
        }
        "#;

        let request: ContactFormRequest = serde_json::from_str(json).unwrap();
        assert_eq!(request.name, "John Doe");
        assert_eq!(request.email, "john@example.com");
        assert_eq!(request.subject, "Test Subject");
        assert_eq!(request.message, "Test message");
        assert_eq!(request.recipient, Some("admin@example.com".to_string()));
    }

    #[test]
    fn test_support_form_request_deserialization() {
        let json = r#"
        {
            "name": "Jane Smith",
            "email": "jane@example.com",
            "subject": "Support Request",
            "message": "I need help with something",
            "priority": "high",
            "category": "technical"
        }
        "#;

        let request: SupportFormRequest = serde_json::from_str(json).unwrap();
        assert_eq!(request.name, "Jane Smith");
        assert_eq!(request.email, "jane@example.com");
        assert_eq!(request.subject, "Support Request");
        assert_eq!(request.message, "I need help with something");
        assert_eq!(request.priority, Some("high".to_string()));
        assert_eq!(request.category, Some("technical".to_string()));
    }

    #[test]
    fn test_custom_email_request_deserialization() {
        let json = r#"
        {
            "to": "user@example.com",
            "to_name": "User Name",
            "subject": "Custom Email",
            "text_body": "Plain text content",
            "html_body": "<p>HTML content</p>",
            "cc": ["cc1@example.com", "cc2@example.com"],
            "bcc": ["bcc@example.com"],
            "reply_to": "reply@example.com"
        }
        "#;

        let request: CustomEmailRequest = serde_json::from_str(json).unwrap();
        assert_eq!(request.to, "user@example.com");
        assert_eq!(request.to_name, Some("User Name".to_string()));
        assert_eq!(request.subject, "Custom Email");
        assert_eq!(request.text_body, Some("Plain text content".to_string()));
        assert_eq!(request.html_body, Some("<p>HTML content</p>".to_string()));
        assert_eq!(
            request.cc,
            Some(vec![
                "cc1@example.com".to_string(),
                "cc2@example.com".to_string()
            ])
        );
        assert_eq!(request.bcc, Some(vec!["bcc@example.com".to_string()]));
        assert_eq!(request.reply_to, Some("reply@example.com".to_string()));
    }

    #[test]
    fn test_notification_request_deserialization() {
        let json = r#"
        {
            "to": "user@example.com",
            "title": "Important Notification",
            "message": "This is an important notification",
            "content": "Additional content here"
        }
        "#;

        let request: NotificationRequest = serde_json::from_str(json).unwrap();
        assert_eq!(request.to, "user@example.com");
        assert_eq!(request.title, "Important Notification");
        assert_eq!(request.message, "This is an important notification");
        assert_eq!(request.content, Some("Additional content here".to_string()));
    }
}
