// src/auth/handlers/register.rs
use bcrypt::{hash, DEFAULT_COST};
use tonic::{Response, Status};
use common::proto::komp_ac::auth::{RegisterRequest, AuthResponse};
use crate::db::PgPool;
use crate::auth::models::AuthError;

const DEFAULT_ROLE: &str = "accountant";

pub async fn register(
    pool: &PgPool,
    payload: RegisterRequest,
) -> Result<Response<AuthResponse>, Status> {
    // Validate passwords match
    if payload.password != payload.password_confirmation {
        return Err(Status::invalid_argument(AuthError::PasswordMismatch.to_string()));
    }

    // Hash password
    let password_hash = hash(payload.password, DEFAULT_COST)
        .map_err(|e| Status::internal(AuthError::HashingError(e.to_string()).to_string()))?;

    let role_to_insert = if payload.role.is_empty() { DEFAULT_ROLE } else { &payload.role };

    // Insert user
    let user = sqlx::query!(
        r#"
        INSERT INTO users (username, email, password_hash, role)
        VALUES ($1, $2, $3, $4)
        RETURNING id, username, email, role
        "#,
        payload.username,
        payload.email,
        password_hash,
        role_to_insert
    )
    .fetch_one(pool)
    .await
    .map_err(|e| {
        if let Some(db_err) = e.as_database_error() {
            if db_err.constraint() == Some("valid_roles") {
                return Status::invalid_argument(format!("Invalid role specified: '{}'", role_to_insert));
            }
        }
        if e.to_string().contains("duplicate key") {
            Status::already_exists(AuthError::UserExists.to_string())
        } else {
            Status::internal(AuthError::DatabaseError(e.to_string()).to_string())
        }
    })?;

    Ok(Response::new(AuthResponse {
        id: user.id.to_string(),
        username: user.username,
        email: user.email.unwrap_or_default(),
        role: user.role,
    }))
}
