using Managing.Application.Abstractions.Repositories;
using Managing.Domain.MoneyManagements;
using Managing.Domain.Users;
using Managing.Infrastructure.Databases.MongoDb;
using Managing.Infrastructure.Databases.MongoDb.Abstractions;
using Managing.Infrastructure.Databases.MongoDb.Collections;

namespace Managing.Infrastructure.Databases;

public class SettingsRepository : ISettingsRepository
{
    private readonly IMongoRepository<MoneyManagementDto> _moneyManagementRepository;

    public SettingsRepository(IMongoRepository<MoneyManagementDto> moneyManagementRepository)
    {
        _moneyManagementRepository = moneyManagementRepository;
    }

    public void DeleteMoneyManagement(string name)
    {
        var moneyManagement = _moneyManagementRepository.FindOne(m => m.Name == name);
        _moneyManagementRepository.DeleteById(moneyManagement.Id.ToString());
    }

    public void DeleteMoneyManagements()
    {
        _moneyManagementRepository.DropCollection();
    }

    public async Task<MoneyManagement> GetMoneyManagement(string name)
    {
        var moneyManagement = await _moneyManagementRepository.FindOneAsync(m => m.Name == name);
        return MongoMappers.Map(moneyManagement);
    }

    public IEnumerable<MoneyManagement> GetMoneyManagements()
    {
        var moneyManagements = _moneyManagementRepository.FindAll();
        return moneyManagements.Select(m => MongoMappers.Map(m));
    }

    public async Task InsertMoneyManagement(MoneyManagement request)
    {
        await _moneyManagementRepository.InsertOneAsync(MongoMappers.Map(request));
    }

    public void UpdateMoneyManagement(MoneyManagement moneyManagement)
    {
        var mm = _moneyManagementRepository.FindOne(m => m.Name == moneyManagement.Name);
        var dto = MongoMappers.Map(moneyManagement);
        dto.Id = mm.Id;
        _moneyManagementRepository.Update(dto);
    }
    
    // User-specific implementations
    public async Task<MoneyManagement> GetMoneyManagementByUser(User user, string name)
    {
        var moneyManagement = await _moneyManagementRepository.FindOneAsync(m => 
            m.Name == name && 
            m.User != null && 
            m.User.Name == user.Name);
            
        return MongoMappers.Map(moneyManagement);
    }

    public IEnumerable<MoneyManagement> GetMoneyManagementsByUser(User user)
    {
        var moneyManagements = _moneyManagementRepository.AsQueryable()
            .Where(m => m.User != null && m.User.Name == user.Name)
            .ToList();
            
        return moneyManagements.Select(m => MongoMappers.Map(m));
    }

    public void DeleteMoneyManagementByUser(User user, string name)
    {
        var moneyManagement = _moneyManagementRepository.FindOne(m => 
            m.Name == name && 
            m.User != null && 
            m.User.Name == user.Name);
            
        if (moneyManagement != null)
        {
            _moneyManagementRepository.DeleteById(moneyManagement.Id.ToString());
        }
    }

    public void DeleteMoneyManagementsByUser(User user)
    {
        var moneyManagements = _moneyManagementRepository.AsQueryable()
            .Where(m => m.User != null && m.User.Name == user.Name)
            .ToList();
            
        foreach (var moneyManagement in moneyManagements)
        {
            _moneyManagementRepository.DeleteById(moneyManagement.Id.ToString());
        }
    }
}
