use actix_web::{Error, HttpRequest};
use base64::Engine;
use base64::engine::general_purpose::STANDARD;
use db::database::AppDatabase;
use models::projects::{project, project_history_name};
use models::repos::repo;
use sea_orm::*;
use sha2::{Digest, Sha256};

pub async fn get_repo_model(
    namespace: &str,
    repo_name: &str,
    db: &AppDatabase,
) -> Result<repo::Model, Error> {
    let project_id = if let Some(project_model) = project::Entity::find()
        .filter(project::Column::Name.eq(namespace))
        .one(db.reader())
        .await
        .map_err(|_| actix_web::error::ErrorInternalServerError("Database error"))?
    {
        project_model.id
    } else if let Some(history) = project_history_name::Entity::find()
        .filter(project_history_name::Column::HistoryName.eq(namespace))
        .one(db.reader())
        .await
        .map_err(|_| actix_web::error::ErrorInternalServerError("Database error"))?
    {
        history.project_uid
    } else {
        return Err(actix_web::error::ErrorNotFound("Project not found").into());
    };

    let repo = repo::Entity::find()
        .filter(repo::Column::RepoName.eq(repo_name))
        .filter(repo::Column::Project.eq(project_id))
        .one(db.reader())
        .await
        .map_err(|_| actix_web::error::ErrorInternalServerError("Database error"))?
        .ok_or_else(|| actix_web::error::ErrorNotFound("Repository not found"))?;

    Ok(repo)
}

pub fn hash_access_key(access_key: &str) -> String {
    let mut hasher = Sha256::new();
    hasher.update(access_key.as_bytes());
    STANDARD.encode(hasher.finalize())
}

pub fn extract_basic_credentials(req: &HttpRequest) -> Result<(String, String), Error> {
    let auth_header = req
        .headers()
        .get("authorization")
        .ok_or_else(|| actix_web::error::ErrorUnauthorized("Missing authorization header"))?
        .to_str()
        .map_err(|_| actix_web::error::ErrorUnauthorized("Invalid authorization header"))?;

    let encoded = auth_header
        .strip_prefix("Basic ")
        .ok_or_else(|| actix_web::error::ErrorUnauthorized("Invalid authorization scheme"))?;

    let decoded = STANDARD
        .decode(encoded)
        .map_err(|_| actix_web::error::ErrorUnauthorized("Invalid basic authorization encoding"))?;

    let decoded = String::from_utf8(decoded)
        .map_err(|_| actix_web::error::ErrorUnauthorized("Invalid basic authorization payload"))?;

    let (username, access_key) = decoded
        .split_once(':')
        .ok_or_else(|| actix_web::error::ErrorUnauthorized("Invalid basic authorization format"))?;

    if username.is_empty() || access_key.is_empty() {
        return Err(actix_web::error::ErrorUnauthorized(
            "Username or access key is empty",
        ));
    }

    Ok((username.to_string(), access_key.to_string()))
}
