use nostr_sdk::prelude::{
    EventBuilder, Kind, RelayUrl, Tag, TagKind, TagStandard, Url,
    nostr::hashes::sha256::Hash as Sha256Hash,
};
use std::borrow::Cow;
use std::collections::HashMap;

#[derive(Default, Clone)]
pub struct SiteManifest {
    pub relays: Vec<Url>,
    pub servers: Vec<Url>,
    pub files: HashMap<String, Sha256Hash>,
    pub title: Option<String>,
    pub description: Option<String>,
    pub source: Option<String>,
}

impl From<SiteManifest> for EventBuilder {
    fn from(manifest: SiteManifest) -> Self {
        let mut tags: Vec<Tag> = Vec::new();

        for (path, sha256) in &manifest.files {
            tags.push(Tag::custom(
                TagKind::Custom(Cow::Borrowed("path")),
                [path, &sha256.to_string()],
            ));
        }

        for url in manifest.servers {
            tags.push(Tag::from_standardized(TagStandard::Server(url)));
        }

        for url in manifest.relays {
            let Ok(relay_url) = RelayUrl::parse(&url.to_string()) else {
                continue;
            };

            tags.push(Tag::from_standardized(TagStandard::Relay(relay_url)));
        }

        if let Some(title) = manifest.title {
            tags.push(Tag::from_standardized(TagStandard::Title(title)));
        }

        if let Some(description) = manifest.description {
            tags.push(Tag::from_standardized(TagStandard::Description(
                description,
            )));
        }

        EventBuilder::new(Kind::Custom(15128), "").tags(tags)
    }
}

impl SiteManifest {
    pub fn add_file(&mut self, path: impl ToString, hash: Sha256Hash) {
        self.files.insert(path.to_string(), hash);
    }

    pub fn with_title(mut self, title: impl ToString) -> Self {
        self.title = Some(title.to_string());
        self
    }

    pub fn with_description(mut self, description: impl ToString) -> Self {
        self.description = Some(description.to_string());
        self
    }

    pub fn with_source(mut self, source: impl ToString) -> Self {
        self.source = Some(source.to_string());
        self
    }
}
