use std::collections::HashMap;
use std::fs;
use std::path::Path;

use base64::{engine::general_purpose, Engine as _};
use directories::UserDirs;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct DockerConfig {
    auths: HashMap<String, DockerAuth>,
}

#[derive(Serialize, Deserialize)]
struct DockerAuth {
    auth: Option<String>,
}

#[derive(Serialize, Deserialize)]
pub(crate) struct DockerPassword {
    pub username: String,
    pub password: String,
}

/// read authentication info from local docker config file
pub(crate) fn read_config() -> Option<DockerPassword> {
    let user_dirs = UserDirs::new().unwrap();
    let home_dir = user_dirs.home_dir();
    let config_path = home_dir.join(".docker").join("config.json");

    if !Path::new(&config_path).exists() {
        return None;
    }

    let config_context = fs::read_to_string(config_path);
    let docker_config: DockerConfig =
        serde_json::from_str(config_context.unwrap().as_str()).unwrap();
    let auths = docker_config.auths;
    let auth = match auths.get("https://index.docker.io/v1/") {
        None => {
            return None;
        }
        Some(docker_auth) => docker_auth.auth.clone().unwrap(),
    };
    let mut buffer = Vec::<u8>::new();
    let _result = general_purpose::URL_SAFE_NO_PAD.decode_vec(auth.as_bytes(), &mut buffer);
    let decoded = match std::str::from_utf8(&buffer) {
        Ok(v) => v,
        Err(e) => panic!("Invalid UTF-8 sequence: {e}"),
    };
    let idx = match decoded.find(':') {
        None => {
            panic!("Invalid authentication: {decoded}")
        }
        Some(i) => i,
    };
    Some(DockerPassword {
        username: String::from(&decoded[0..idx]),
        password: String::from(&decoded[(idx + 1)..]),
    })
}
