use dfir_windows_types::Guid;

use crate::{cache::ValueSet, CDatabase};

pub trait ToStringOrStringSet {
    fn to_string_or_stringset(&self, database: &CDatabase<'_, '_>) -> StringOrStringSet;
}

pub enum StringOrStringSet {
    String(String),
    StringSet(Vec<String>),
}

impl ToStringOrStringSet for String {
    fn to_string_or_stringset(&self, _database: &CDatabase<'_, '_>) -> StringOrStringSet {
        StringOrStringSet::String(self.to_string())
    }
}

impl ToStringOrStringSet for u32 {
    fn to_string_or_stringset(&self, _database: &CDatabase<'_, '_>) -> StringOrStringSet {
        StringOrStringSet::String(self.to_string())
    }
}

impl ToStringOrStringSet for i32 {
    fn to_string_or_stringset(&self, _database: &CDatabase<'_, '_>) -> StringOrStringSet {
        StringOrStringSet::String(self.to_string())
    }
}

impl ToStringOrStringSet for i64 {
    fn to_string_or_stringset(&self, _database: &CDatabase<'_, '_>) -> StringOrStringSet {
        StringOrStringSet::String(self.to_string())
    }
}

impl ToStringOrStringSet for bool {
    fn to_string_or_stringset(&self, _database: &CDatabase<'_, '_>) -> StringOrStringSet {
        StringOrStringSet::String(self.to_string())
    }
}

impl ToStringOrStringSet for Guid {
    fn to_string_or_stringset(&self, _database: &CDatabase<'_, '_>) -> StringOrStringSet {
        StringOrStringSet::String(self.to_string())
    }
}

impl<T> ToStringOrStringSet for ValueSet<T>
where
    T: ToStringOrStringSet + Eq + PartialEq,
{
    fn to_string_or_stringset(&self, database: &CDatabase<'_, '_>) -> StringOrStringSet {
        StringOrStringSet::StringSet(
            self.iter()
                .flat_map(|e| match e.to_string_or_stringset(database) {
                    StringOrStringSet::String(s) => vec![s],
                    StringOrStringSet::StringSet(items) => items,
                })
                .collect(),
        )
    }
}
