using System.Data;
using System.Text;
using e_suite.API.Common;
using e_suite.API.Common.exceptions;
using e_suite.API.Common.extensions;
using e_suite.API.Common.models;
using e_suite.Database.Audit;
using e_suite.Database.Core.Extensions;
using e_suite.Service.SigmaImporter.Helpers;
using e_suite.Service.SigmaImporter.Repository;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace e_suite.Service.SigmaImporter.GmgProfiles;

public class GmgProfileImporter : IGmgProfileImporter
{
    private readonly ISigmaFileBrowserRepository _sigmaFileBrowserURepository;
    private readonly IGlossariesManager _glossariesManager;
    private readonly IConfiguration _configuration;
    private readonly ILogger _logger;
    private readonly IImportGlossaryHelper _glossaryHelper;

    public GmgProfileImporter(ISigmaFileBrowserRepository sigmaFileBrowserURepository, IGlossariesManager glossariesManager, IConfiguration configuration, ILogger logger, IImportGlossaryHelper glossaryHelper)
    {
        _sigmaFileBrowserURepository = sigmaFileBrowserURepository;
        _glossariesManager = glossariesManager;
        _configuration = configuration;
        _logger = logger;
        _glossaryHelper = glossaryHelper;
    }
    
    public async Task DoGmgProfileImport(AuditUserDetails auditUserDetails)
    {
        //Check if there is a MySql database setting present, if not, do nothing.
        var server = _configuration.GetConfigValue($"SigmaFileBrowser_SERVER", $"SigmaFileBrowser:Server", "");
        if (string.IsNullOrWhiteSpace(server))
        {
            _logger.LogInformation("SigmaFileBrowser_SERVER is not set, skipping import");
            //System is not setup to connect to the mySql database, data import cannot take place.
            return;
        }


        var gmgProfileGlossaryItem = await EnsureGmgProfilesSystemGlossaryExists(auditUserDetails) ?? throw new NotFoundException("Gmg Profile Glossary does not exist in e-suite!");
        var gmgProfileGlossaryItemGeneralIdRef = gmgProfileGlossaryItem.ToGeneralIdRef()!;

        //Get the list of GMG Profiles from sigma
        var gmgProfiles = await _sigmaFileBrowserURepository.GetActiveGmgProfiles() ?? throw new NotFoundException("The GMG Profile glossary not found from Sigma");

        var gmgProfileItems = new List<NewGlossaryItem>();
        foreach (var gmgProfile in gmgProfiles)
        {
            var existingGmgProfileItem =
                gmgProfileGlossaryItem.Children?.SingleOrDefault(x => x.Name == gmgProfile.CompiledName);
            if (existingGmgProfileItem == null)
            {
                //Glossary doesn't exist in e-suite, so import it.
                var gmgProfileItem = new NewGlossaryItem
                {
                    Parent = gmgProfileGlossaryItemGeneralIdRef,
                    Name = gmgProfile.CompiledName
                };

                //Check to ensure the item is not already added.
                if (!CheckExists(gmgProfileItems, gmgProfileItem)) 
                    gmgProfileItems.Add(gmgProfileItem);
            }
        }

        AssertNoDuplicateNames(gmgProfileItems);

        await _glossariesManager.AddGlossaryItems(auditUserDetails, gmgProfileItems,
            CancellationToken.None);
    }

    private static bool CheckExists(List<NewGlossaryItem> gmgProfileItems, NewGlossaryItem gmgProfileItem)
    {
        return gmgProfileItems.Any(x => x.Name == gmgProfileItem.Name);
    }

    private void AssertNoDuplicateNames(List<NewGlossaryItem> gmgProfileItems)
    {
        var duplicates = gmgProfileItems
            .GroupBy(x => x.Name)
            .Where(x => x.Count() > 1)
            .ToDictionary(x => x.Key, y => y.Count());

        if (duplicates.Count > 0)
        {
            var sb = new StringBuilder();

            foreach (var duplicate in duplicates)
            {
                sb.AppendFormat("{0}: {1}\r\n", duplicate.Key, duplicate.Value);
            }

            throw new DuplicateNameException($"Duplicates found: {sb}");
        }
    }

    public readonly Guid GmgProfileGuid = new("BBA078CF-8326-40B8-92EC-ECD9A2017702");

    private async Task<GlossaryItem?> EnsureGmgProfilesSystemGlossaryExists(AuditUserDetails auditUserDetails)
    {
        
        var glossary = new NewGlossaryItem
        {
            Parent = _glossaryHelper.SystemGlossaryGeneralIdRef,
            Guid = GmgProfileGuid,
            Name = "GMG Profile"
        };

        return await _glossaryHelper.EnsureGlossaryItemExists(auditUserDetails, glossary);
    }
}