use std::path::Path;
use log::{debug, info};
use oci_distribution::{secrets::RegistryAuth, Client, Reference};
use tokio::{fs::File, io::AsyncReadExt};
use url::Url;
use crate::{
    error::{Error, Result},
    oci::wasm::pull::pull_wasm_from_registry,
};
use self::push::push_wasm_to_registry;
use super::{auth::get_auth_info_by_url, default_schema_port, get_client};
pub mod pull;
pub mod push;
pub fn parse_img_url(url: &str) -> Result<(Client, RegistryAuth, Reference, String)> {
    let img_url = Url::parse(url).map_err(|e| Error::InvalidParam(e.to_string()))?;
    let auth = match get_auth_info_by_url(&img_url) {
        Ok((username, password)) => {
            println!("auth with username: {}", username);
            RegistryAuth::Basic(username, password)
        }
        Err(err) => {
            if matches!(err, Error::LoginInfoNotFound(_)) {
                RegistryAuth::Anonymous
            } else {
                return Err(err);
            }
        }
    };
    debug!("Parsed auth info: {:?}", auth);
    let client = get_client(&img_url)?;
    let Some(host) = img_url.host() else {
        return Err(Error::InvalidParam(format!("invalid url: {}",url)))
    };
    let repo_url = format!(
        "{}:{}{}",
        host,
        img_url
            .port()
            .unwrap_or(default_schema_port(img_url.scheme())?),
        img_url.path()
    );
    Ok((
        client,
        auth,
        repo_url
            .parse::<Reference>()
            .map_err(|e| Error::InvalidParam(e.to_string()))?,
        repo_url,
    ))
}
pub async fn wasm_push(file: String, img_url: String) -> Result<()> {
    let path = Path::new(file.as_str());
    let mut module = vec![];
    if path.exists() && path.is_file() {
        info!("read content from file {}", file);
        let mut f = File::open(path).await.map_err(Error::IOErr)?;
        f.read_to_end(&mut module).await.map_err(Error::IOErr)?;
    } else {
        return Err(Error::InvalidParam(format!(
            "file {} not exist or is not regular file",
            file
        )));
    }
    let (mut client, auth, reference, repo_url) = parse_img_url(img_url.as_str())?;
    info!("pushing to {}", repo_url);
    let url = push_wasm_to_registry(&mut client, &auth, &reference, module, None).await?;
    info!("successful push to {}", repo_url);
    println!("successfully push to to {}", url);
    Ok(())
}
pub async fn wasm_pull(img: &str) -> Result<Vec<u8>> {
    let (mut client, auth, reference, repo_url) = parse_img_url(img)?;
    info!("pulling from {}", repo_url);
    let img_content = pull_wasm_from_registry(&mut client, &auth, &reference).await?;
    info!(
        "successful pull {} bytes from {}",
        img_content.len(),
        repo_url
    );
    Ok(img_content)
}