//! Email handlers module
//!
//! This module provides HTTP handlers for email-related functionality including
//! form submissions, contact forms, and general email sending endpoints.

pub mod handlers;
pub mod routes;

use std::net::SocketAddr;

use axum::{extract::ConnectInfo, http::HeaderMap};
pub use handlers::{
    get_email_status, send_contact_form, send_custom_email, send_notification, send_support_form,
};
pub use routes::create_email_routes;
use serde::Serialize;

/// Email API error response
#[derive(Debug, Serialize)]
pub struct EmailErrorResponse {
    pub error: String,
    pub message: String,
    pub code: String,
}

impl EmailErrorResponse {
    pub fn new(error: &str, message: &str, code: &str) -> Self {
        Self {
            error: error.to_string(),
            message: message.to_string(),
            code: code.to_string(),
        }
    }

    pub fn validation_error(message: &str) -> Self {
        Self::new("Validation Error", message, "VALIDATION_ERROR")
    }

    pub fn email_error(message: &str) -> Self {
        Self::new("Email Error", message, "EMAIL_ERROR")
    }

    #[allow(dead_code)]
    pub fn internal_error(message: &str) -> Self {
        Self::new("Internal Error", message, "INTERNAL_ERROR")
    }
}

/// Email API success response
#[derive(Debug, Serialize)]
pub struct EmailSuccessResponse {
    pub message: String,
    pub message_id: String,
    pub status: String,
}

impl EmailSuccessResponse {
    pub fn new(message: &str, message_id: &str, status: &str) -> Self {
        Self {
            message: message.to_string(),
            message_id: message_id.to_string(),
            status: status.to_string(),
        }
    }
}

/// Extract IP address from request
pub fn extract_ip_address(
    headers: &HeaderMap,
    connect_info: Option<ConnectInfo<SocketAddr>>,
) -> Option<String> {
    // Check for X-Forwarded-For header first (proxy/load balancer)
    if let Some(forwarded) = headers.get("x-forwarded-for") {
        if let Ok(forwarded_str) = forwarded.to_str() {
            // Take the first IP from the comma-separated list
            if let Some(ip) = forwarded_str.split(',').next() {
                return Some(ip.trim().to_string());
            }
        }
    }

    // Check for X-Real-IP header
    if let Some(real_ip) = headers.get("x-real-ip") {
        if let Ok(ip_str) = real_ip.to_str() {
            return Some(ip_str.to_string());
        }
    }

    // Fall back to connection info
    if let Some(ConnectInfo(addr)) = connect_info {
        return Some(addr.ip().to_string());
    }

    None
}

/// Extract user agent from request
pub fn extract_user_agent(headers: &HeaderMap) -> Option<String> {
    headers
        .get("user-agent")
        .and_then(|ua| ua.to_str().ok())
        .map(|ua| ua.to_string())
}

/// Extract language preference from request headers
pub fn extract_language_from_headers(headers: &HeaderMap) -> String {
    // Check for Accept-Language header
    if let Some(accept_lang) = headers.get("accept-language") {
        if let Ok(lang_str) = accept_lang.to_str() {
            // Parse Accept-Language header (e.g., "en-US,en;q=0.9,es;q=0.8")
            let preferred_lang = lang_str
                .split(',')
                .next()
                .unwrap_or("en")
                .split(';')
                .next()
                .unwrap_or("en")
                .split('-')
                .next()
                .unwrap_or("en")
                .trim()
                .to_lowercase();

            // Validate and return supported language
            match preferred_lang.as_str() {
                "en" | "es" | "fr" | "de" | "it" | "pt" | "ru" | "ja" | "ko" | "zh" => {
                    preferred_lang
                }
                _ => "en".to_string(), // Default fallback
            }
        } else {
            "en".to_string()
        }
    } else {
        "en".to_string() // Default fallback
    }
}

/// Extract language from user profile or session
/// This would typically integrate with your user authentication system
#[allow(dead_code)]
pub fn extract_language_from_user(_user_id: Option<&str>) -> String {
    // TODO: Implement user profile language detection
    // This would query the user's language preference from the database
    // For now, return default language
    "en".to_string()
}

/// Determine the best language to use for email templates
/// Priority: user profile > request headers > default
#[allow(dead_code)]
pub fn determine_email_language(headers: &HeaderMap, user_id: Option<&str>) -> String {
    // First try user profile language
    if user_id.is_some() {
        let user_lang = extract_language_from_user(user_id);
        if !user_lang.is_empty() && user_lang != "en" {
            return user_lang;
        }
    }

    // Fall back to header language
    extract_language_from_headers(headers)
}

/// Basic rate limiting check (simple implementation)
/// In production, you might want to use a more sophisticated rate limiter
pub fn check_rate_limit(_ip: &str) -> bool {
    // TODO: Implement proper rate limiting
    // For now, just return true (no rate limiting)
    true
}

/// Validate email format
pub fn validate_email(email: &str) -> bool {
    if email.is_empty() || email.len() > 254 {
        return false;
    }

    // Must contain exactly one @
    let at_count = email.matches('@').count();
    if at_count != 1 {
        return false;
    }

    let parts: Vec<&str> = email.split('@').collect();
    let local = parts[0];
    let domain = parts[1];

    // Local part validation
    if local.is_empty() || local.len() > 64 {
        return false;
    }

    // Domain part validation
    if domain.is_empty() || domain.len() > 253 {
        return false;
    }

    // Domain must contain at least one dot and not start/end with dot
    if !domain.contains('.') || domain.starts_with('.') || domain.ends_with('.') {
        return false;
    }

    // Basic character validation
    let valid_chars = |c: char| c.is_alphanumeric() || ".-_+".contains(c);
    local.chars().all(valid_chars)
        && domain
            .chars()
            .all(|c| c.is_alphanumeric() || ".-".contains(c))
}

/// Validate required string field
pub fn validate_required_field(field: &str, field_name: &str) -> Result<(), String> {
    if field.trim().is_empty() {
        return Err(format!("{} is required", field_name));
    }
    if field.len() > 1000 {
        return Err(format!("{} is too long (max 1000 characters)", field_name));
    }
    Ok(())
}

/// Validate message length
pub fn validate_message_length(message: &str) -> Result<(), String> {
    if message.trim().is_empty() {
        return Err("Message is required".to_string());
    }
    if message.len() > 5000 {
        return Err("Message is too long (max 5000 characters)".to_string());
    }
    Ok(())
}

/// Common validation for form submissions
pub fn validate_form_submission(
    name: &str,
    email: &str,
    subject: &str,
    message: &str,
) -> Result<(), String> {
    validate_required_field(name, "Name")?;
    validate_required_field(email, "Email")?;
    validate_required_field(subject, "Subject")?;
    validate_message_length(message)?;

    if !validate_email(email) {
        return Err("Invalid email format".to_string());
    }

    Ok(())
}

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

    #[test]
    fn test_validate_email() {
        assert!(validate_email("test@example.com"));
        assert!(validate_email("user.name@domain.co.uk"));
        assert!(!validate_email("invalid-email"));
        assert!(!validate_email("@example.com"));
        assert!(!validate_email("test@"));
        assert!(!validate_email(""));
    }

    #[test]
    fn test_validate_required_field() {
        assert!(validate_required_field("Valid Name", "Name").is_ok());
        assert!(validate_required_field("", "Name").is_err());
        assert!(validate_required_field("   ", "Name").is_err());

        // Test long field
        let long_string = "a".repeat(1001);
        assert!(validate_required_field(&long_string, "Name").is_err());
    }

    #[test]
    fn test_validate_message_length() {
        assert!(validate_message_length("Valid message").is_ok());
        assert!(validate_message_length("").is_err());
        assert!(validate_message_length("   ").is_err());

        // Test long message
        let long_message = "a".repeat(5001);
        assert!(validate_message_length(&long_message).is_err());
    }

    #[test]
    fn test_validate_form_submission() {
        assert!(validate_form_submission(
            "John Doe",
            "john@example.com",
            "Test Subject",
            "Test message"
        )
        .is_ok());

        assert!(
            validate_form_submission("", "john@example.com", "Test Subject", "Test message")
                .is_err()
        );

        assert!(validate_form_submission(
            "John Doe",
            "invalid-email",
            "Test Subject",
            "Test message"
        )
        .is_err());
    }

    #[test]
    fn test_extract_language_from_headers() {
        use axum::http::HeaderMap;

        let mut headers = HeaderMap::new();

        // Test with no Accept-Language header
        assert_eq!(extract_language_from_headers(&headers), "en");

        // Test with simple language
        headers.insert("accept-language", "es".parse().unwrap());
        assert_eq!(extract_language_from_headers(&headers), "es");

        // Test with complex Accept-Language header
        headers.insert(
            "accept-language",
            "fr-FR,fr;q=0.9,en;q=0.8".parse().unwrap(),
        );
        assert_eq!(extract_language_from_headers(&headers), "fr");

        // Test with unsupported language (should fall back to English)
        headers.insert("accept-language", "xy-ZZ".parse().unwrap());
        assert_eq!(extract_language_from_headers(&headers), "en");
    }

    #[test]
    fn test_determine_email_language() {
        use axum::http::HeaderMap;

        let mut headers = HeaderMap::new();
        headers.insert("accept-language", "es-ES,es;q=0.9".parse().unwrap());

        // Test with no user ID (should use header language)
        assert_eq!(determine_email_language(&headers, None), "es");

        // Test with user ID (currently returns header language as user profile is not
        // implemented)
        assert_eq!(determine_email_language(&headers, Some("user123")), "es");
    }
}
