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

/// Role model for permission-based access control
#[derive(Debug, Clone, Serialize, Deserialize, SurrealValue)]
#[surreal(crate = "surrealdb::types")]
pub struct Role {
    pub id: Option<RecordId>,
    pub role_id: Uuid,
    pub name: String,
    pub description: Option<String>,
    pub permissions: Vec<String>,
    pub is_system: bool,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

/// Role creation request
#[derive(Debug, Validate, Deserialize)]
pub struct CreateRoleRequest {
    #[validate(length(min = 2, max = 50))]
    pub name: String,
    #[validate(length(max = 200))]
    pub description: Option<String>,
    pub permissions: Option<Vec<String>>,
}

/// Role update request
#[derive(Debug, Validate, Deserialize)]
pub struct UpdateRoleRequest {
    #[validate(length(min = 2, max = 50))]
    pub name: Option<String>,
    #[validate(length(max = 200))]
    pub description: Option<String>,
    pub permissions: Option<Vec<String>>,
}

/// Role response
#[derive(Debug, Serialize)]
pub struct RoleResponse {
    pub id: Uuid,
    pub name: String,
    pub description: Option<String>,
    pub permissions: Vec<String>,
    pub is_system: bool,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

impl From<Role> for RoleResponse {
    fn from(role: Role) -> Self {
        Self {
            id: role.role_id,
            name: role.name,
            description: role.description,
            permissions: role.permissions,
            is_system: role.is_system,
            created_at: role.created_at,
            updated_at: role.updated_at,
        }
    }
}

impl Role {
    /// Create a new role
    pub fn new(
        name: String,
        description: Option<String>,
        permissions: Option<Vec<String>>,
        is_system: bool,
    ) -> Self {
        let now = Utc::now();
        Self {
            id: None,
            role_id: Uuid::new_v4(),
            name,
            description,
            permissions: permissions.unwrap_or_default(),
            is_system,
            created_at: now,
            updated_at: now,
        }
    }

    /// Update role data
    pub fn update(&mut self, request: UpdateRoleRequest) {
        if let Some(name) = request.name {
            self.name = name;
        }
        if let Some(description) = request.description {
            self.description = Some(description);
        }
        if let Some(permissions) = request.permissions {
            self.permissions = permissions;
        }
        self.updated_at = Utc::now();
    }

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

    /// Add permission to role
    pub fn add_permission(&mut self, permission: String) {
        if !self.permissions.contains(&permission) {
            self.permissions.push(permission);
            self.updated_at = Utc::now();
        }
    }

    /// Remove permission from role
    pub fn remove_permission(&mut self, permission: &str) {
        self.permissions.retain(|p| p != permission);
        self.updated_at = Utc::now();
    }

    /// Create system roles (called during initialization)
    pub fn create_system_roles() -> Vec<Self> {
        vec![
            Self::new(
                "admin".to_string(),
                Some("Full system administrator access".to_string()),
                Some(vec![
                    "users:read".to_string(),
                    "users:write".to_string(),
                    "users:delete".to_string(),
                    "roles:read".to_string(),
                    "roles:write".to_string(),
                    "roles:delete".to_string(),
                    "permissions:read".to_string(),
                    "system:manage".to_string(),
                ]),
                true,
            ),
            Self::new(
                "user".to_string(),
                Some("Standard user with basic permissions".to_string()),
                Some(vec![
                    "profile:read".to_string(),
                    "profile:write".to_string(),
                ]),
                true,
            ),
            Self::new(
                "operator".to_string(),
                Some("System operator with read access".to_string()),
                Some(vec![
                    "users:read".to_string(),
                    "roles:read".to_string(),
                    "permissions:read".to_string(),
                    "system:read".to_string(),
                ]),
                true,
            ),
        ]
    }
}
