using Ethanol.MalwareSonar.Fuzzy;

public abstract class MalwareModelBuilderBase
{
    public abstract MalwareModel Build();
}


public class MalwareModelBuilder : MalwareModelBuilderBase
{
    private readonly string _family;
    private readonly List<MalwareIndicators> _indicators;

    public string Description { get; set; } = string.Empty;

    /// <summary>
    /// The URL link to further information about the malware family. We will use MalwareBaazar for this. THe format of the link is:
    /// https://bazaar.abuse.ch/browse/signature/[FamilyName]/
    /// </summary>
    public string Url => $"https://bazaar.abuse.ch/browse/signature/{FamilyName}";

    public string FamilyName { get; init; }

    public MalwareModelBuilder(string family, string familyName)
    {
        _family = family;
        FamilyName = familyName;
        _indicators = new List<MalwareIndicators>();
    }

    /// <summary>
    /// Builds a MalwareModel from the indicators added to the builder.
    /// </summary>
    /// <returns>A MalwareModel object representing the built malware model.</returns>
    public override MalwareModel Build()
    {
        var sampleCount = _indicators.Count();

        var urlsFrequency = _indicators.SelectMany(x => x.Urls).GroupBy(x => x, x => x, (k, v) => new KeyValuePair<string, int>(k.ToString(), v.Count())).ToDictionary(x => x.Key, x => x.Value);
        var domainsFrequency = _indicators.SelectMany(x => x.Domains).GroupBy(x => x, x => x, (k, v) => new KeyValuePair<string, int>(k, v.Count())).ToDictionary(x => x.Key, x => x.Value);
        var ipsFrequency = _indicators.SelectMany(x => x.Ips).GroupBy(x => x, x => x, (k, v) => new KeyValuePair<string, int>(k, v.Count())).ToDictionary(x => x.Key, x => x.Value);

        var urlsFuzzySet = new FuzzySet<string>(new FrequencyBasedMembership<string>(urlsFrequency, 0, sampleCount), urlsFrequency.Select(x => x.Key));
        var domainsFuzzySet = new FuzzySet<string>(new FrequencyBasedMembership<string>(domainsFrequency, 0, sampleCount), domainsFrequency.Select(x => x.Key));
        var ipsFuzzySet = new FuzzySet<string>(new FrequencyBasedMembership<string>(ipsFrequency, 0, sampleCount), ipsFrequency.Select(x => x.Key));

        var urlsTresholdsArray = _indicators.Select(x => x.Urls.Select(x => urlsFuzzySet.GetMembership(x)).Sum()).ToArray();
        var domainsTresholdsArray = _indicators.Select(x => x.Domains.Select(x => domainsFuzzySet.GetMembership(x)).Sum()).ToArray();
        var ipsTresholdsArray = _indicators.Select(x => x.Ips.Select(x => ipsFuzzySet.GetMembership(x)).Sum()).ToArray();

        return new MalwareModel
        {
            Family = _family,
            Name = FamilyName,
            Description = Description,
            InformationRefUrl = Url,
            Domains = domainsFuzzySet,
            Urls = urlsFuzzySet,
            Ips = ipsFuzzySet,
            DomainThresholds = domainsTresholdsArray,
            UrlThresholds = urlsTresholdsArray,
            IpsThresholds = ipsTresholdsArray
        };
    }

    public void AddMalwareIndicators(IEnumerable<MalwareIndicators> indicators)
    {
        _indicators.AddRange(indicators);
    }
}

