use db::sqlx;
use model::users::UserModel;
use serde::{Deserialize, Serialize};

use crate::{AppService, error::AppError};

#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
pub struct UserSummaryResponse {
    pub username: String,
    pub display_name: String,
    pub avatar_url: String,
    pub website_url: String,
    #[schema(value_type = String)]
    pub created_at: chrono::DateTime<chrono::Utc>,
}

impl AppService {
    pub async fn users_summary_by_username(
        &self,
        username: &str,
    ) -> Result<UserSummaryResponse, AppError> {
        let user = self.users_find_active_user_by_username(username).await?;
        Ok(user.into())
    }

    /// Get a user's avatar URL by username.
    pub async fn users_get_avatar_url(
        &self,
        username: &str,
    ) -> Result<String, AppError> {
        let user = self.users_find_active_user_by_username(username).await?;
        if user.avatar_url.is_empty() {
            return Err(AppError::NotFound("avatar not found".to_string()));
        }
        Ok(user.avatar_url)
    }

    pub async fn users_find_active_user_by_username(
        &self,
        username: &str,
    ) -> Result<UserModel, AppError> {
        let user = sqlx::query_as::<_, UserModel>(
            "SELECT id, username, display_name, avatar_url, website_url, allow_use, can_search, \
                    last_sign_in_at, created_at, updated_at \
             FROM \"user\" WHERE username = $1",
        )
        .bind(username)
        .fetch_optional(self.db.reader())
        .await
        .map_err(|e| AppError::DatabaseError(e.to_string()))?
        .ok_or(AppError::UserNotFound)?;

        if !user.allow_use {
            return Err(AppError::UserNotFound);
        }
        Ok(user)
    }
}

impl From<UserModel> for UserSummaryResponse {
    fn from(value: UserModel) -> Self {
        Self {
            username: value.username,
            display_name: value.display_name,
            avatar_url: value.avatar_url,
            website_url: value.website_url,
            created_at: value.created_at,
        }
    }
}
