use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
use uuid::Uuid;
use validator::Validate;

// ============ 消息 DTO ============

/// 消息响应
#[derive(Debug, Serialize, ToSchema)]
pub struct MessageResp {
    pub id: Uuid,
    pub tenant_id: Uuid,
    pub template_id: Option<Uuid>,
    pub sender_id: Option<Uuid>,
    pub sender_type: String,
    pub recipient_id: Uuid,
    pub recipient_type: String,
    pub title: String,
    pub body: String,
    pub priority: String,
    pub business_type: Option<String>,
    pub business_id: Option<Uuid>,
    pub is_read: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub read_at: Option<DateTime<Utc>>,
    pub is_archived: bool,
    pub status: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub sent_at: Option<DateTime<Utc>>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub version: i32,
}

/// 发送消息请求
#[derive(Debug, Deserialize, Validate, ToSchema)]
pub struct SendMessageReq {
    #[validate(length(min = 1, max = 200, message = "标题不能为空且不超过200字符"))]
    pub title: String,
    #[validate(length(min = 1, message = "内容不能为空"))]
    pub body: String,
    pub recipient_id: Uuid,
    #[serde(default = "default_recipient_type")]
    #[validate(custom(function = "validate_recipient_type"))]
    pub recipient_type: String,
    #[serde(default = "default_priority")]
    #[validate(custom(function = "validate_priority"))]
    pub priority: String,
    pub template_id: Option<Uuid>,
    pub business_type: Option<String>,
    pub business_id: Option<Uuid>,
}

fn validate_recipient_type(value: &str) -> Result<(), validator::ValidationError> {
    match value {
        "user" | "role" | "department" | "all" => Ok(()),
        _ => Err(validator::ValidationError::new("invalid_recipient_type")),
    }
}

fn validate_priority(value: &str) -> Result<(), validator::ValidationError> {
    match value {
        "normal" | "important" | "urgent" => Ok(()),
        _ => Err(validator::ValidationError::new("invalid_priority")),
    }
}

fn default_recipient_type() -> String {
    "user".to_string()
}

fn default_priority() -> String {
    "normal".to_string()
}

/// 消息列表查询参数
#[derive(Debug, Deserialize, ToSchema, utoipa::IntoParams)]
pub struct MessageQuery {
    pub page: Option<u64>,
    pub page_size: Option<u64>,
    pub is_read: Option<bool>,
    pub priority: Option<String>,
    pub business_type: Option<String>,
    pub status: Option<String>,
}

impl MessageQuery {
    /// 获取安全的分页大小（上限 100）。
    pub fn safe_page_size(&self) -> u64 {
        self.page_size.unwrap_or(20).min(100)
    }
}

/// 未读消息计数响应
#[derive(Debug, Serialize, ToSchema)]
pub struct UnreadCountResp {
    pub count: i64,
}

// ============ 消息模板 DTO ============

/// 消息模板响应
#[derive(Debug, Serialize, ToSchema)]
pub struct MessageTemplateResp {
    pub id: Uuid,
    pub tenant_id: Uuid,
    pub name: String,
    pub code: String,
    pub channel: String,
    pub title_template: String,
    pub body_template: String,
    pub language: String,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub version: i32,
}

/// 创建消息模板请求
#[derive(Debug, Deserialize, Validate, ToSchema)]
pub struct CreateTemplateReq {
    #[validate(length(min = 1, max = 100, message = "名称不能为空且不超过100字符"))]
    pub name: String,
    #[validate(length(min = 1, max = 50, message = "编码不能为空且不超过50字符"))]
    pub code: String,
    #[serde(default = "default_channel")]
    #[validate(custom(function = "validate_channel"))]
    pub channel: String,
    #[validate(length(min = 1, max = 200, message = "标题模板不能为空"))]
    pub title_template: String,
    #[validate(length(min = 1, message = "内容模板不能为空"))]
    pub body_template: String,
    #[serde(default = "default_language")]
    pub language: String,
}

fn default_channel() -> String {
    "in_app".to_string()
}

fn validate_channel(value: &str) -> Result<(), validator::ValidationError> {
    match value {
        "in_app" | "email" | "sms" | "wechat" => Ok(()),
        _ => Err(validator::ValidationError::new("invalid_channel")),
    }
}

fn default_language() -> String {
    "zh-CN".to_string()
}

/// 更新消息模板请求
#[derive(Debug, Deserialize, Validate, ToSchema)]
pub struct UpdateTemplateReq {
    #[validate(length(min = 1, max = 100, message = "名称不能为空且不超过100字符"))]
    pub name: Option<String>,
    #[validate(length(min = 1, max = 200, message = "标题模板不能为空"))]
    pub title_template: Option<String>,
    #[validate(length(min = 1, message = "内容模板不能为空"))]
    pub body_template: Option<String>,
    #[validate(length(min = 1, max = 10, message = "语言代码无效"))]
    pub language: Option<String>,
    #[validate(custom(function = "validate_channel"))]
    pub channel: Option<String>,
    pub version: i32,
}

// ============ 消息订阅偏好 DTO ============

/// 消息订阅偏好响应
#[derive(Debug, Serialize, ToSchema)]
pub struct MessageSubscriptionResp {
    pub id: Uuid,
    pub tenant_id: Uuid,
    pub user_id: Uuid,
    pub notification_types: Option<serde_json::Value>,
    pub channel_preferences: Option<serde_json::Value>,
    pub dnd_enabled: bool,
    pub dnd_start: Option<String>,
    pub dnd_end: Option<String>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub version: i32,
}

/// 更新消息订阅偏好请求
#[derive(Debug, Deserialize, Validate, ToSchema)]
pub struct UpdateSubscriptionReq {
    pub notification_types: Option<serde_json::Value>,
    pub channel_preferences: Option<serde_json::Value>,
    pub dnd_enabled: Option<bool>,
    #[validate(length(max = 8, message = "免打扰开始时间格式无效"))]
    pub dnd_start: Option<String>,
    #[validate(length(max = 8, message = "免打扰结束时间格式无效"))]
    pub dnd_end: Option<String>,
    pub version: i32,
}

#[cfg(test)]
mod tests {
    use super::*;
    use uuid::Uuid;
    use validator::Validate;

    // ============ SendMessageReq 测试 ============

    fn valid_send_message_req() -> SendMessageReq {
        SendMessageReq {
            title: "系统通知".to_string(),
            body: "您有一条新消息".to_string(),
            recipient_id: Uuid::now_v7(),
            recipient_type: "user".to_string(),
            priority: "normal".to_string(),
            template_id: None,
            business_type: None,
            business_id: None,
        }
    }

    #[test]
    fn send_message_req_valid() {
        let req = valid_send_message_req();
        assert!(req.validate().is_ok());
    }

    #[test]
    fn send_message_req_empty_title_fails() {
        let mut req = valid_send_message_req();
        req.title = "".to_string();
        assert!(req.validate().is_err());
    }

    #[test]
    fn send_message_req_title_too_long_fails() {
        let mut req = valid_send_message_req();
        req.title = "x".repeat(201);
        assert!(req.validate().is_err());
    }

    #[test]
    fn send_message_req_title_max_length_ok() {
        let mut req = valid_send_message_req();
        req.title = "x".repeat(200);
        assert!(req.validate().is_ok());
    }

    #[test]
    fn send_message_req_empty_body_fails() {
        let mut req = valid_send_message_req();
        req.body = "".to_string();
        assert!(req.validate().is_err());
    }

    #[test]
    fn send_message_req_valid_recipient_types() {
        for rt in &["user", "role", "department", "all"] {
            let mut req = valid_send_message_req();
            req.recipient_type = rt.to_string();
            assert!(
                req.validate().is_ok(),
                "recipient_type '{}' should be valid",
                rt
            );
        }
    }

    #[test]
    fn send_message_req_invalid_recipient_type_fails() {
        let mut req = valid_send_message_req();
        req.recipient_type = "invalid".to_string();
        assert!(req.validate().is_err());
    }

    #[test]
    fn send_message_req_valid_priorities() {
        for p in &["normal", "important", "urgent"] {
            let mut req = valid_send_message_req();
            req.priority = p.to_string();
            assert!(req.validate().is_ok(), "priority '{}' should be valid", p);
        }
    }

    #[test]
    fn send_message_req_invalid_priority_fails() {
        let mut req = valid_send_message_req();
        req.priority = "critical".to_string();
        assert!(req.validate().is_err());
    }

    #[test]
    fn send_message_req_default_recipient_type_is_user() {
        assert_eq!(default_recipient_type(), "user");
    }

    #[test]
    fn send_message_req_default_priority_is_normal() {
        assert_eq!(default_priority(), "normal");
    }

    // ============ MessageQuery 测试 ============

    #[test]
    fn message_query_safe_page_size_default() {
        let query = MessageQuery {
            page: None,
            page_size: None,
            is_read: None,
            priority: None,
            business_type: None,
            status: None,
        };
        assert_eq!(query.safe_page_size(), 20);
    }

    #[test]
    fn message_query_safe_page_size_custom() {
        let query = MessageQuery {
            page: None,
            page_size: Some(50),
            is_read: None,
            priority: None,
            business_type: None,
            status: None,
        };
        assert_eq!(query.safe_page_size(), 50);
    }

    #[test]
    fn message_query_safe_page_size_capped_at_100() {
        let query = MessageQuery {
            page: None,
            page_size: Some(200),
            is_read: None,
            priority: None,
            business_type: None,
            status: None,
        };
        assert_eq!(query.safe_page_size(), 100);
    }

    #[test]
    fn message_query_safe_page_size_exactly_100() {
        let query = MessageQuery {
            page: None,
            page_size: Some(100),
            is_read: None,
            priority: None,
            business_type: None,
            status: None,
        };
        assert_eq!(query.safe_page_size(), 100);
    }

    // ============ CreateTemplateReq 测试 ============

    fn valid_create_template_req() -> CreateTemplateReq {
        CreateTemplateReq {
            name: "欢迎模板".to_string(),
            code: "WELCOME".to_string(),
            channel: "in_app".to_string(),
            title_template: "欢迎加入".to_string(),
            body_template: "您好，{{name}}，欢迎加入平台".to_string(),
            language: "zh-CN".to_string(),
        }
    }

    #[test]
    fn create_template_req_valid() {
        let req = valid_create_template_req();
        assert!(req.validate().is_ok());
    }

    #[test]
    fn create_template_req_empty_name_fails() {
        let mut req = valid_create_template_req();
        req.name = "".to_string();
        assert!(req.validate().is_err());
    }

    #[test]
    fn create_template_req_name_too_long_fails() {
        let mut req = valid_create_template_req();
        req.name = "x".repeat(101);
        assert!(req.validate().is_err());
    }

    #[test]
    fn create_template_req_name_max_length_ok() {
        let mut req = valid_create_template_req();
        req.name = "x".repeat(100);
        assert!(req.validate().is_ok());
    }

    #[test]
    fn create_template_req_empty_code_fails() {
        let mut req = valid_create_template_req();
        req.code = "".to_string();
        assert!(req.validate().is_err());
    }

    #[test]
    fn create_template_req_code_too_long_fails() {
        let mut req = valid_create_template_req();
        req.code = "X".repeat(51);
        assert!(req.validate().is_err());
    }

    #[test]
    fn create_template_req_code_max_length_ok() {
        let mut req = valid_create_template_req();
        req.code = "X".repeat(50);
        assert!(req.validate().is_ok());
    }

    #[test]
    fn create_template_req_valid_channels() {
        for ch in &["in_app", "email", "sms", "wechat"] {
            let mut req = valid_create_template_req();
            req.channel = ch.to_string();
            assert!(req.validate().is_ok(), "channel '{}' should be valid", ch);
        }
    }

    #[test]
    fn create_template_req_invalid_channel_fails() {
        let mut req = valid_create_template_req();
        req.channel = "telegram".to_string();
        assert!(req.validate().is_err());
    }

    #[test]
    fn create_template_req_empty_title_template_fails() {
        let mut req = valid_create_template_req();
        req.title_template = "".to_string();
        assert!(req.validate().is_err());
    }

    #[test]
    fn create_template_req_title_template_too_long_fails() {
        let mut req = valid_create_template_req();
        req.title_template = "x".repeat(201);
        assert!(req.validate().is_err());
    }

    #[test]
    fn create_template_req_empty_body_template_fails() {
        let mut req = valid_create_template_req();
        req.body_template = "".to_string();
        assert!(req.validate().is_err());
    }

    #[test]
    fn create_template_req_default_channel_is_in_app() {
        assert_eq!(default_channel(), "in_app");
    }

    #[test]
    fn create_template_req_default_language_is_zh_cn() {
        assert_eq!(default_language(), "zh-CN");
    }

    // ============ 自定义验证函数测试 ============

    #[test]
    fn validate_recipient_type_valid() {
        for rt in &["user", "role", "department", "all"] {
            assert!(
                validate_recipient_type(rt).is_ok(),
                "'{}' should be a valid recipient type",
                rt
            );
        }
    }

    #[test]
    fn validate_recipient_type_invalid() {
        assert!(validate_recipient_type("invalid").is_err());
        assert!(validate_recipient_type("").is_err());
        assert!(validate_recipient_type("USER").is_err());
    }

    #[test]
    fn validate_priority_valid() {
        for p in &["normal", "important", "urgent"] {
            assert!(
                validate_priority(p).is_ok(),
                "'{}' should be a valid priority",
                p
            );
        }
    }

    #[test]
    fn validate_priority_invalid() {
        assert!(validate_priority("critical").is_err());
        assert!(validate_priority("").is_err());
        assert!(validate_priority("NORMAL").is_err());
    }

    #[test]
    fn validate_channel_valid() {
        for ch in &["in_app", "email", "sms", "wechat"] {
            assert!(
                validate_channel(ch).is_ok(),
                "'{}' should be a valid channel",
                ch
            );
        }
    }

    #[test]
    fn validate_channel_invalid() {
        assert!(validate_channel("slack").is_err());
        assert!(validate_channel("").is_err());
        assert!(validate_channel("EMAIL").is_err());
    }
}
