using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore;
using ms_namingservice.Objects;

namespace ms_namingservice.Database;

/// <summary>
/// Class for querying the database.
/// </summary>
public class RulesQuery
{
    /// <summary>
    /// Represents the logger instance for this class.
    /// </summary>
    private static ILogger Logger = Logging.LoggerFactory.CreateLogger<RulesQuery>();

    /// <summary>
    /// Configuration to get the database connection string.
    /// </summary>
    private static IConfigurationRoot Configuration = new ConfigurationBuilder()
        .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
        .AddJsonFile("appsettings.json", true, true)
        .Build();
    
    /// <summary>
    /// Setting the database connection.
    /// </summary>
    private static DbContextOptionsBuilder<RulesContext> OptionsBuilder =
        new DbContextOptionsBuilder<RulesContext>().UseNpgsql(Configuration.GetConnectionString("Database"));

    /// <summary>
    /// DbContext class instance for the database communication
    /// </summary>
    private static RulesContext Context = new(OptionsBuilder.Options);


    /// <summary>
    /// Method, that gets the short type of the LES category (SA/OA/ND/OS) from the database.
    /// </summary>
    /// <param name="logSourceType">The log source type.</param>
    /// <returns>The short type of the LES category.</returns>
    public static async Task<string> GetLesShortType(string logSourceType)
    {
        {
            var result = await Context.LesTypes
                .Where(l => l.Type == logSourceType)
                .Select(l => l.ShortType)
                .FirstOrDefaultAsync();
            Logger.LogDebug("SQL query returned: " + result); //Log
            return result;
        }
    }

    /// <summary>
    /// Method, that gets the short name of the LES (lin, win, cisco, proxy...) from the database.
    /// </summary>
    /// <param name="logSourceName">The log source name.</param>
    /// <returns>The short name of the LES.</returns>
    public static async Task<string> GetLesShortName(string logSourceName)
    {
        var result = await Context.LesTypesCategories
            .Where(l => l.Category == logSourceName)
            .Select(l => l.ShortCategory)
            .FirstOrDefaultAsync();
        Logger.LogDebug("SQL query returned: " + result); //Log
        return result;
    }

    /// <summary>
    /// Method, that gets the category of the use case (Credential Access, Abusive Content...) from the database.
    /// </summary>
    /// <param name="tag">The tag value.</param>
    /// <param name="framework">The framework type.</param>
    /// <returns>The category of the UC.</returns>
    public static async Task<string> GetCategory(string tag, string framework)
    {
        var result = await Context.FrameworkType2FrameworkMetadataTypes.Where(f =>
                f.Value == tag && f.FrameworkType.Type == framework && f.FrameworkMetadataType.Type == "Category")
            .Select(f => f.Value)
            .FirstOrDefaultAsync();
        Logger.LogDebug("SQL query returned: " + result); //Log
        return result;
    }

    /// <summary>
    /// Method, that gets the short category value of the use case (c&c, fraud...) from the database.
    /// </summary>
    /// <param name="category">The category value.</param>
    /// <param name="framework">The framework type.</param>
    /// <returns>The short name of the category of the UC.</returns>
    public static async Task<string> GetCategoryShort(string category, string framework)
    {
        var result = await Context.FrameworkType2FrameworkMetadataTypes.Where(f =>
                f.Value == category && f.FrameworkType.Type == framework &&
                f.FrameworkMetadataType.Type == "Category")
            .Select(f => f.ValueShort)
            .FirstOrDefaultAsync();
        Logger.LogDebug("SQL query returned: " + result); //Log
        return result;
    }

    /// <summary>
    /// Method, that gets the short subcategory value for the use case from the database.
    /// </summary>
    /// <param name="tag">The tag value.</param>
    /// <param name="framework">The framework value.</param>
    /// <returns></returns>
    public static async Task<string> GetSubcategoryShort(string tag, string framework)
    {
        //Deleting subtechnique tags (e.g. from attack.t000.000 makes attack.t000)
        var pattern = @"(.*\.t\d+)(\.\d+)?"; //Regex
        var FormattedTag = Regex.Replace(tag, pattern, "$1");
        
        var result = await Context.FrameworkType2FrameworkMetadataTypes.Where(f =>
                f.Value == FormattedTag && f.FrameworkType.Type == framework &&
                f.FrameworkMetadataType.Type == "Subcategory")
            .Select(f => f.ValueShort)
            .FirstOrDefaultAsync();

        if (result == null)
        {
            result = "oth"; //If the subcategory is not recognized
        } 
        
        Logger.LogDebug("SQL query returned: " + result); //Log
        return result;
    }
}