using adas_core.Application.Repositories.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.MongoModels;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoUtils = adas_core.Infrastructure.Utils.MongoUtils;

namespace adas_core.Infrastructure.Repositories;

public class HistoricalConfigChangesRepository : MongoRepository<HistoricalConfigChanges>,
    IHistoricalConfigChangesRepository
{
    private readonly ApiSettings _apiSettings;
    private readonly ILogger<HistoricalConfigChangesRepository> _logger;

    public HistoricalConfigChangesRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database,
        ILogger<HistoricalConfigChangesRepository> logger) : base(database)
    {
        if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
        _apiSettings = apiSettings.Value;
        _logger = logger;
    }


    public override string GetCollectionName()
    {
        return _apiSettings.HistoricalConfigChanges ?? "historicalConfigChanges";
    }

    public override async Task<HistoricalConfigChanges?> InsertOneAsync(HistoricalConfigChanges historicalConfigChanges)
    {
        try
        {
            await Collection.InsertOneAsync(historicalConfigChanges);
            return await FindById(historicalConfigChanges.Id);
        }
        catch (Exception ex)
        {
            _logger.LogError("Error inserting historicalConfigChanges {exMessage}", ex.Message);
            return null;
        }
    }


    public async Task<HistoricalConfigChanges?> Delete(ObjectId id)
    {
        return await DeleteAsync(id);
    }

    public async Task<ICollection<HistoricalConfigChanges>> FindAll()
    {
        var result = await Collection.FindAsync(_ => true);
        return await result.ToListAsync();
    }

    public async Task<List<ObjectId>> FindAllIds()
    {
        List<ObjectId> listCollection = [];
        var allCollection = await Collection.FindAsync(_ => true);

        listCollection.AddRange(allCollection.ToList().Select(item => item.Id));

        return listCollection;
    }

    public async Task<HistoricalConfigChanges?> FindById(ObjectId id)
    {
        var result = await Collection.FindAsync(Builders<HistoricalConfigChanges>.Filter.Eq(x => x.Id, id));
        return await result.FirstOrDefaultAsync();
    }


    public async Task<HistoricalConfigChanges?> Update(HistoricalConfigChanges historicalConfigChanges)
    {
        var filter = Builders<HistoricalConfigChanges>.Filter.Eq("_id", historicalConfigChanges.Id);
        var update = Builders<HistoricalConfigChanges>.Update
            .Set(c => c, historicalConfigChanges);

        return await Collection.FindOneAndUpdateAsync(
            filter,
            update,
            new FindOneAndUpdateOptions<HistoricalConfigChanges, HistoricalConfigChanges>
            {
                ReturnDocument = ReturnDocument.After
            });
    }

    public async Task<ICollection<HistoricalConfigChanges>> FindLastHistoricalConfigChangesByType(
        DisplayConfigEnums.ConfigTypes cfgType, int num = 10)
    {
        var filterDefinitionBuilder = Builders<HistoricalConfigChanges>.Filter;
        var filter = filterDefinitionBuilder.Eq(c => c.ConfigType, cfgType);

        var result = await Collection.FindAsync(
            filter,
            new FindOptions<HistoricalConfigChanges>
                { Sort = Builders<HistoricalConfigChanges>.Sort.Descending("time"), Limit = num }
        );

        return await result.ToListAsync();
    }

    public async Task<ICollection<HistoricalConfigChanges>> FindLastHistoricalConfigChangesByUser(string user,
        DisplayConfigEnums.ConfigTypes? cfgType = null, int num = 10)
    {
        var filterDefinitionBuilder = Builders<HistoricalConfigChanges>.Filter;
        var filter = filterDefinitionBuilder.Eq(c => c.Username, user);

        if (cfgType != null) filter &= filterDefinitionBuilder.Eq(c => c.ConfigType, cfgType.Value);

        var result = await Collection.FindAsync(
            filter,
            new FindOptions<HistoricalConfigChanges>
                { Sort = Builders<HistoricalConfigChanges>.Sort.Descending("time"), Limit = num }
        );

        return await result.ToListAsync();
    }

    public override async Task CreateIndexes()
    {
        try
        {
            var options = new CreateIndexOptions { Background = true, Unique = false };
            var indexes = new List<CreateIndexModel<HistoricalConfigChanges>>
            {
                new("{ configType: 1, time:-1 }", options),
                new("{ username: 1, time: -1 }", options)
            };
            await MongoUtils.EnsureIndexes(Collection, indexes);
        }
        catch (Exception e)
        {
            _logger.LogError(
                "error creating indexes for HistoricalConfigChanges collection {eMessage} TRACE: {eStackTrace}",
                e.Message, e.StackTrace);
            throw;
        }
    }
}