using e_suite.API.Common.repository;
using e_suite.Database.Audit;
using e_suite.Database.Core;
using e_suite.Database.Core.Extensions;
using e_suite.Database.Core.Tables.CustomFields;
using e_suite.Database.Core.Tables.Glossaries;
using eSuite.Core.Miscellaneous;
using Microsoft.EntityFrameworkCore;
using e_suite.Database.Audit.Models;
using e_suite.Database.Core.Helpers;

namespace e_suite.Modules.GlossariesManager.Repository;

public class GlossariesManagerRepository : RepositoryBase, IGlossariesManagerRepository
{
    public GlossariesManagerRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext)
    {
    }

    public async Task AddGlossaryItem(AuditUserDetails auditUserDetails, Glossary glossary, CancellationToken cancellationToken)
    {
        var items = new List<Glossary>
        {
            glossary
        };
        await AddGlossaryItems(auditUserDetails, items, cancellationToken);
    }

    public async Task AddGlossaryItems(AuditUserDetails auditUserDetails, IEnumerable<Glossary> items, CancellationToken cancellationToken)
    {
        foreach (var item in items)
            await DatabaseDbContext.Glossaries.AddAsync(item, cancellationToken);

        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task<Glossary?> GetParentGlossary(IGeneralIdRef? glossaryItemParent, CancellationToken cancellationToken)
    {
        return glossaryItemParent == null
            ? null
            : await FindGlossary(glossaryItemParent, cancellationToken);
    }

    public async Task<Glossary?> FindGlossary(IGeneralIdRef glossaryItem, CancellationToken cancellationToken) =>
        await DatabaseDbContext.Glossaries
            .Include(x => x.CustomFieldDefinitions)
            .ThenInclude(x => x.CustomField)
            .Include(x => x.CustomFieldValues)
            .Include(x => x.Parent)
            .ThenInclude( x=> x.CustomFieldDefinitions)
            .ThenInclude( x=> x.CustomField)
            .FindByGeneralIdRefAsync(glossaryItem, cancellationToken);

    public Task<IEnumerable<Glossary>> FindGlossaryChildren(long parentId, CancellationToken cancellationToken)
    {
        return Task.FromResult<IEnumerable<Glossary>>( DatabaseDbContext.Glossaries
            .Include(x => x.CustomFieldDefinitions)
            .ThenInclude(x => x.CustomField)
            .Include(x => x.CustomFieldValues)
            .Where(x => x.ParentId == parentId) );
    }

    public async Task<List<CustomField>> GetCustomFieldDefinitions(IEnumerable<IGeneralIdRef> customFieldIdRefs, CancellationToken cancellationToken)
    {
        var list = new List<CustomField>();

        foreach (var customFieldIdRef in customFieldIdRefs)
        {
            var customFieldDefinition = await DatabaseDbContext.CustomFields.FindByGeneralIdRefAsync(customFieldIdRef, cancellationToken);
            if (customFieldDefinition != null)
                list.Add(customFieldDefinition);
        }

        return list;
    }

    public IQueryable<GlossaryCustomField> GetGlossaryCustomFields(long glossaryId)
    {
        return DatabaseDbContext.GlossaryCustomFields
            .Where(x => x.GlossaryId == glossaryId);
    }

    public async Task SaveChildCustomFieldDefinitions(AuditUserDetails auditUserDetails, IReadOnlyList<GlossaryCustomField> removalList, IReadOnlyList<GlossaryCustomField> additionList,
        CancellationToken cancellationToken)
    {
        DatabaseDbContext.GlossaryCustomFields.RemoveRange(removalList);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
        await DatabaseDbContext.GlossaryCustomFields.AddRangeAsync(additionList, cancellationToken);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task<List<GlossaryCustomFieldValue>> GetGlossaryCustomValues(IId glossary, CancellationToken cancellationToken)
    {
        return await DatabaseDbContext.GlossaryCustomFieldValues.Where(x => x.GlossaryId == glossary.Id).ToListAsync(cancellationToken);
    }

    public async Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, IEnumerable<Delta<GlossaryCustomFieldValue>> deltas, CancellationToken cancellationToken)
    {
        foreach (var delta in deltas)
        {
            await delta.UpdateDbSetAsync(DatabaseDbContext.GlossaryCustomFieldValues, cancellationToken);
        }

        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta<GlossaryCustomFieldValue> delta, CancellationToken cancellationToken)
    {
        var deltas = new List<Delta<GlossaryCustomFieldValue>>
        {
            delta
        };

        await SaveCustomFieldValues(auditUserDetails, deltas, cancellationToken);
    }

    public async Task EditGlossaryItem(AuditUserDetails auditUserDetails, Glossary glossaryItem, CancellationToken cancellationToken)
    {
        var item = await DatabaseDbContext.Glossaries.FindByGeneralIdRefAsync(new GeneralIdRef { Guid = glossaryItem.Guid, Id = glossaryItem.Id }, cancellationToken);

        if (item != null)
        {
            item.Name = glossaryItem.Name;
            item.Deleted = glossaryItem.Deleted;
        }

        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }
}