use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use surrealdb::types::{RecordId, SurrealValue};
use uuid::Uuid;
use validator::Validate;

/// User model for SurrealDB storage
#[derive(Debug, Clone, Serialize, Deserialize, SurrealValue)]
#[surreal(crate = "surrealdb::types")]
pub struct User {
    pub id: Option<RecordId>,
    pub user_id: Uuid,
    pub email: String,
    pub username: String,
    pub password_hash: String,
    pub first_name: Option<String>,
    pub last_name: Option<String>,
    pub is_active: bool,
    pub is_verified: bool,
    pub roles: Vec<String>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub last_login: Option<DateTime<Utc>>,
}

/// User creation request
#[derive(Debug, Validate, Deserialize)]
pub struct CreateUserRequest {
    #[validate(email)]
    pub email: String,
    #[validate(length(min = 3, max = 50))]
    pub username: String,
    #[validate(length(min = 8, max = 128))]
    pub password: String,
    #[validate(length(max = 50))]
    pub first_name: Option<String>,
    #[validate(length(max = 50))]
    pub last_name: Option<String>,
    pub roles: Option<Vec<String>>,
}

/// User update request
#[derive(Debug, Default, Validate, Deserialize)]
pub struct UpdateUserRequest {
    #[validate(email)]
    pub email: Option<String>,
    #[validate(length(min = 3, max = 50))]
    pub username: Option<String>,
    #[validate(length(min = 8, max = 128))]
    pub password: Option<String>,
    #[validate(length(max = 50))]
    pub first_name: Option<String>,
    #[validate(length(max = 50))]
    pub last_name: Option<String>,
    pub is_active: Option<bool>,
    pub is_verified: Option<bool>,
    pub roles: Option<Vec<String>>,
}

/// User response (without sensitive data)
#[derive(Debug, Serialize)]
pub struct UserResponse {
    pub id: Uuid,
    pub email: String,
    pub username: String,
    pub first_name: Option<String>,
    pub last_name: Option<String>,
    pub is_active: bool,
    pub is_verified: bool,
    pub roles: Vec<String>,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
    pub last_login: Option<DateTime<Utc>>,
}

impl From<User> for UserResponse {
    fn from(user: User) -> Self {
        Self {
            id: user.user_id,
            email: user.email,
            username: user.username,
            first_name: user.first_name,
            last_name: user.last_name,
            is_active: user.is_active,
            is_verified: user.is_verified,
            roles: user.roles,
            created_at: user.created_at,
            updated_at: user.updated_at,
            last_login: user.last_login,
        }
    }
}

impl User {
    /// Create a new user with hashed password
    pub fn new(
        email: String,
        username: String,
        password_hash: String,
        first_name: Option<String>,
        last_name: Option<String>,
        roles: Option<Vec<String>>,
    ) -> Self {
        let now = Utc::now();
        Self {
            id: None,
            user_id: Uuid::new_v4(),
            email,
            username,
            password_hash,
            first_name,
            last_name,
            is_active: true,
            is_verified: false,
            roles: roles.unwrap_or_else(|| vec!["user".to_string()]),
            created_at: now,
            updated_at: now,
            last_login: None,
        }
    }

    /// Update last login timestamp
    pub fn update_last_login(&mut self) {
        self.last_login = Some(Utc::now());
        self.updated_at = Utc::now();
    }

    /// Update user data
    pub fn update(&mut self, request: UpdateUserRequest) {
        if let Some(email) = request.email {
            self.email = email;
        }
        if let Some(username) = request.username {
            self.username = username;
        }
        if let Some(password_hash) = request.password {
            self.password_hash = password_hash;
        }
        if let Some(first_name) = request.first_name {
            self.first_name = Some(first_name);
        }
        if let Some(last_name) = request.last_name {
            self.last_name = Some(last_name);
        }
        if let Some(is_active) = request.is_active {
            self.is_active = is_active;
        }
        if let Some(is_verified) = request.is_verified {
            self.is_verified = is_verified;
        }
        if let Some(roles) = request.roles {
            self.roles = roles;
        }
        self.updated_at = Utc::now();
    }

    /// Check if user has a specific role
    pub fn has_role(&self, role: &str) -> bool {
        self.roles.contains(&role.to_string())
    }

    /// Check if user has any of the specified roles
    pub fn has_any_role(&self, roles: &[&str]) -> bool {
        roles.iter().any(|role| self.has_role(role))
    }
}

/// Login request
#[derive(Debug, Validate, Deserialize)]
pub struct LoginRequest {
    #[validate(length(min = 1))]
    pub username_or_email: String,
    #[validate(length(min = 1))]
    pub password: String,
}
