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.Helpers;
using e_suite.Database.Core.Tables.Forms;
using eSuite.Core.Miscellaneous;
using Microsoft.EntityFrameworkCore;

namespace e_suite.Modules.FormsManager.Repository;

public class FormRepository : RepositoryBase, IFormRepository
{
    public FormRepository(IEsuiteDatabaseDbContext databaseDbContext) 
        : base(databaseDbContext)
    {
    }


    public async Task CreateNewFormVersionAsync(AuditUserDetails auditUserDetails, FormTemplateVersion formTemplateVersion, CancellationToken cancellationToken)
    {
        await DatabaseDbContext.FormTemplateVersions.AddAsync(formTemplateVersion, cancellationToken);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task CreateTemplateAsync(AuditUserDetails auditUserDetails, FormTemplate template, CancellationToken cancellationToken)
    {
        await DatabaseDbContext.FormTemplates.AddAsync(template, cancellationToken);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task DeleteAllVersionsAsync(AuditUserDetails auditUserDetails, IEnumerable<FormTemplateVersion> formVersions, CancellationToken cancellationToken)
    {
        DatabaseDbContext.FormTemplateVersions.UpdateRange(formVersions);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task EditFormTemplateAsync(AuditUserDetails auditUserDetails, FormTemplate formTemplate, CancellationToken cancellationToken)
    {
        DatabaseDbContext.FormTemplates.Update(formTemplate);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task<FormTemplate?> GetTemplateAsync(IGeneralIdRef id, CancellationToken cancellationToken)
    {
        return await DatabaseDbContext.
            FormTemplates
            //.Include(x => x.Versions)
            .FindByGeneralIdRefAsync(id, cancellationToken);
    }

    public IQueryable<FormTemplate> GetTemplates()
    {
        return DatabaseDbContext.
            FormTemplates
            //.Include( x=> x.Versions)
            .Where(x => !x.Deleted);
    }


    public IQueryable<FormTemplateVersion> GetAllFormVersions(
        long templateId
    )
    {
        return DatabaseDbContext.FormTemplateVersions.Where(f => f.TemplateId == templateId);
    }

    public Task<FormTemplate?> GetTemplateWithOutLoadedRefereranceAsync(IGeneralIdRef id,
        CancellationToken cancellationToken)
        => DatabaseDbContext.FormTemplates.FindByGeneralIdRefAsync(id, cancellationToken);

    public Task<FormTemplateVersion?> GetFormTemplateVersionAsync(IGeneralIdRef templateId, CancellationToken cancellationToken)
        => DatabaseDbContext.FormTemplateVersions.FindByGeneralIdRefAsync(templateId, cancellationToken);

    public Task<FormTemplate?> GetFormTemplateWithSpecificVersionAsync(IGeneralIdRef id, long formTemplateVersionId, CancellationToken cancellationToken)
        => DatabaseDbContext.FormTemplates.FindByGeneralIdRefAsync(id, cancellationToken);

    public async Task AddFormInstance(AuditUserDetails auditUserDetails, FormInstance newFormInstance, CancellationToken cancellationToken)
    {
        await AddFormInstances(auditUserDetails, [newFormInstance], cancellationToken);
    }

    public async Task AddFormInstances(AuditUserDetails auditUserDetails, IEnumerable<FormInstance> newFormInstances, CancellationToken cancellationToken)
    {
        await DatabaseDbContext.FormInstances.AddRangeAsync(newFormInstances, cancellationToken);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task AddFormInstanceValues(
        AuditUserDetails auditUserDetails,
        List<FormFieldInstance> customFieldValues,
        CancellationToken cancellationToken
    )
    {
        await DatabaseDbContext.FormFieldInstances.AddRangeAsync(customFieldValues, cancellationToken);
        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task<FormInstance?> GetFormInstance(GeneralIdRef createFormInstanceId, bool tracking, CancellationToken cancellationToken)
    {
        var formInstances = LookupFormInstances(tracking);
        return await formInstances.FindByGeneralIdRefAsync(createFormInstanceId, cancellationToken);
    }

    private IQueryable<FormInstance> LookupFormInstances(bool tracking)
    {
        IQueryable<FormInstance> formInstances = DatabaseDbContext.FormInstances;

        if (!tracking)
        {
            formInstances = formInstances.AsNoTracking();
        }

        var results = formInstances.Include(x => x.FormTemplateVersion)
            .ThenInclude(x => x.Template)
            //.ThenInclude(x => x.Versions)
            .Include(x => x.FormFields)
            .ThenInclude(x => x.CustomField);
        return results;
    }

    public Task<List<FormInstance>> GetFormInstances(IEnumerable<GeneralIdRef> generalIdRefs, bool tracking, CancellationToken cancellationToken)
    {
        var formInstances = LookupFormInstances(tracking);

        return Task.FromResult(formInstances.FindByGeneralIdRef(generalIdRefs).ToList());

    }

    public async Task SaveCustomFieldValues(AuditUserDetails auditUserDetails, Delta<FormFieldInstance> delta, CancellationToken cancellationToken)
    {
        await delta.UpdateDbSetAsync(DatabaseDbContext.FormFieldInstances, cancellationToken);

        await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
    }

    public async Task<IEnumerable<FormInstance>> GetFormsContainingFieldValue(IGeneralIdRef customFieldGeneralIdRef, string value, CancellationToken cancellationToken)
    {
        var customField = await DatabaseDbContext.CustomFields.FindByGeneralIdRefAsync(customFieldGeneralIdRef, cancellationToken);

        if (customField == null)
            throw new NullReferenceException("Unable to find Custom field");

        var formInstances = DatabaseDbContext.FormFieldInstances
            .Where(x => x.CustomFieldId == customField.Id & x.Value == value)
            .Include(x => x.FormInstance)
            .Select(x => x.FormInstance);

        return formInstances;
    }
}