use dprint_cli_core::checksums::ChecksumPathOrUrl;
use dprint_cli_core::types::ErrBox;
use serde::{self, Deserialize, Serialize};

use crate::environment::Environment;
use crate::types::{BinaryName, Version};

#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct RegistryFile {
    pub schema_version: u32,
    name: String,
    owner: String,
    pub versions: Vec<RegistryVersionInfo>,
}

impl RegistryFile {
    pub fn get_binary_name(&self) -> BinaryName {
        BinaryName::new(self.owner.clone(), self.name.clone())
    }
}

#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct RegistryVersionInfo {
    pub version: Version,
    pub path: String,
    pub checksum: String,
}

impl RegistryVersionInfo {
    pub fn get_url(&self) -> ChecksumPathOrUrl {
        ChecksumPathOrUrl {
            path_or_url: self.path.clone(),
            checksum: Some(self.checksum.clone()),
        }
    }
}

pub async fn download_registry_file<'a, TEnvironment: Environment>(
    environment: &TEnvironment,
    url: &str,
) -> Result<RegistryFile, ErrBox> {
    let plugin_file_bytes = environment.download_file(&url).await?;

    read_registry_file(&plugin_file_bytes)
}

fn read_registry_file(file_bytes: &[u8]) -> Result<RegistryFile, ErrBox> {
    // todo: don't use serde because this should transform up to the latest schema version
    match serde_json::from_slice::<RegistryFile>(&file_bytes) {
        Ok(file) => {
            if file.schema_version != 1 {
                return err!(
                    "Expected schema version 1, but found {}. This may indicate you need to upgrade your CLI version to use this registry file.",
                    file.schema_version
                );
            }

            if file.name.contains("/") || file.owner.contains("/") {
                return err!("The binary owner and name may not contain a forward slash.");
            }

            Ok(file)
        }
        Err(err) => err!("Error deserializing registry file. {}", err.to_string()),
    }
}