use crate::AppService;
use crate::error::AppError;
use chrono::Utc;
use models::users::{user, user_activity_log};
use sea_orm::*;
use serde::{Deserialize, Serialize};
use session::Session;
use uuid::Uuid;

#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct UpdateProfileParams {
    pub avatar_url: Option<String>,
    pub website_url: Option<String>,
    pub organization: Option<String>,
}

#[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)]
pub struct ProfileResponse {
    pub uid: Uuid,
    pub username: String,
    pub display_name: Option<String>,
    pub avatar_url: Option<String>,
    pub website_url: Option<String>,
    pub organization: Option<String>,
    pub created_at: chrono::DateTime<Utc>,
    pub updated_at: chrono::DateTime<Utc>,
    pub last_sign_in_at: Option<chrono::DateTime<Utc>>,
}

impl From<user::Model> for ProfileResponse {
    fn from(user: user::Model) -> Self {
        ProfileResponse {
            uid: user.uid,
            username: user.username,
            display_name: user.display_name,
            avatar_url: user.avatar_url,
            website_url: user.website_url,
            organization: user.organization,
            created_at: user.created_at,
            updated_at: user.updated_at,
            last_sign_in_at: user.last_sign_in_at,
        }
    }
}

impl AppService {
    pub async fn user_get_profile(&self, user_uid: Uuid) -> Result<ProfileResponse, AppError> {
        let user = self.utils_find_user_by_uid(user_uid).await?;
        Ok(ProfileResponse::from(user))
    }
    pub async fn user_get_profile_by_username(
        &self,
        user_name: String,
    ) -> Result<ProfileResponse, AppError> {
        let user = self.utils_find_user_by_username(user_name).await?;
        Ok(ProfileResponse::from(user))
    }
    pub async fn user_get_profile_by_context(
        &self,
        context: &Session,
    ) -> Result<ProfileResponse, AppError> {
        let user_uid = context.user().ok_or(AppError::Unauthorized)?;
        let user = self.utils_find_user_by_uid(user_uid).await?;
        Ok(ProfileResponse::from(user))
    }

    pub async fn user_get_current_profile(
        &self,
        context: &Session,
    ) -> Result<ProfileResponse, AppError> {
        let user_uid = context.user().ok_or(AppError::Unauthorized)?;
        self.user_get_profile(user_uid).await
    }

    pub async fn user_update_profile(
        &self,
        context: &Session,
        params: UpdateProfileParams,
    ) -> Result<ProfileResponse, AppError> {
        let user_uid = context.user().ok_or(AppError::Unauthorized)?;
        let user: user::Model = self.utils_find_user_by_uid(user_uid).await?;

        let mut active_user: user::ActiveModel = user.into();

        if params.avatar_url.is_some() {
            active_user.avatar_url = Set(params.avatar_url.clone());
        }
        if params.website_url.is_some() {
            active_user.website_url = Set(params.website_url.clone());
        }
        if params.organization.is_some() {
            active_user.organization = Set(params.organization.clone());
        }
        active_user.updated_at = Set(Utc::now());

        let updated_user = active_user.update(&self.db).await?;

        let _ = user_activity_log::ActiveModel {
            user_uid: Set(Some(user_uid)),
            action: Set("profile_update".to_string()),
            ip_address: Set(context.ip_address()),
            user_agent: Set(context.user_agent()),
            details: Set(serde_json::json!({
                "updated_fields": {
                    "avatar_url": params.avatar_url.is_some(),
                    "website_url": params.website_url.is_some(),
                    "organization": params.organization.is_some(),
                }
            })),
            created_at: Set(Utc::now()),
            ..Default::default()
        }
        .insert(&self.db)
        .await;

        Ok(ProfileResponse::from(updated_user))
    }
}
