use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, sqlx::FromRow)]
pub struct Profile {
pub display_name: String,
pub tagline_ko: Option<String>,
pub tagline_en: Option<String>,
pub avatar_url: Option<String>,
pub bio_ko: Option<String>,
pub bio_en: Option<String>,
pub email: Option<String>,
pub github_username: Option<String>,
pub linkedin_url: Option<String>,
#[sqlx(json)]
pub education: Vec<Education>,
#[sqlx(json)]
pub custom_links: Vec<CustomLink>,
pub updated_at: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Education {
pub institution: Option<String>,
pub degree: Option<String>,
pub field: Option<String>,
pub start_year: Option<i32>,
pub end_year: Option<i32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CustomLink {
pub label: String,
pub url: String,
pub icon: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ProfileInput {
pub expected_updated_at: String,
pub display_name: String,
pub tagline_ko: Option<String>,
pub tagline_en: Option<String>,
pub avatar_url: Option<String>,
pub bio_ko: Option<String>,
pub bio_en: Option<String>,
pub email: Option<String>,
pub github_username: Option<String>,
pub linkedin_url: Option<String>,
#[serde(default)]
pub education: Vec<Education>,
#[serde(default)]
pub custom_links: Vec<CustomLink>,
}
pub fn validate_email(s: &str) -> bool {
let mut parts = s.split('@');
let local = parts.next().unwrap_or("");
let domain = parts.next().unwrap_or("");
let mut dparts = domain.split('.');
let d0 = dparts.next().unwrap_or("");
let d1 = dparts.next().unwrap_or("");
!local.is_empty() && !d0.is_empty() && !d1.is_empty() && !s.contains(' ')
}
pub fn validate_year_range(start: Option<i32>, end: Option<i32>) -> bool {
match (start, end) {
(Some(s), Some(e)) => s <= e,
_ => true,
}
}