using adas_core.Application.Repositories.Interfaces;
using adas_core.Domain.Models;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.MongoModels;
using Microsoft.Extensions.Options;
using MongoDB.Driver;
using Newtonsoft.Json;
using Serilog;

namespace adas_core.Infrastructure.Repositories;

public class SectionRepository : MongoRepository<Section>, ISectionRepository
{
    private readonly ApiSettings _apiSettings;

    public SectionRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database) : base(database)
    {
        if (apiSettings == null) throw new ArgumentNullException(nameof(apiSettings));
        _apiSettings = apiSettings.Value;
    } //For testing

   


    public override string GetCollectionName()
    {
        return _apiSettings.ConfigSections ?? "config_sections";
    }

    public async Task<List<Section>> GetAll()
    {
        var result = await Collection.FindAsync(Builders<Section>.Filter.Empty);

        return result.ToList();
    }

    public async Task<Section?> FindBySection(string section)
    {
        var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x.SectionTitle, section));

        return await result.FirstOrDefaultAsync();
    }

    public async Task<Section?> FindByPointOfCare(string pointOfCare)
    {
        var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x.PointOfCare, pointOfCare));

        return await result.FirstOrDefaultAsync();
    }

    public async Task<Section?> FindById(string id)
    {
        var result = await Collection.FindAsync(Builders<Section>.Filter.Eq(x => x.Id, id));

        return await result.FirstOrDefaultAsync();
    }

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

    public async Task<List<Section>> FindByLocation(PatientLocation location)
    {
        //can not filter to Collection the where condition, it throws System.InvalidOperationException: '{}.pointOfCare is not supported.'
        var sections = await GetAll();

        return sections.Where(section =>
            (section.PointOfCare == location.UnitName && section.Items.Any(item =>
                item.Boxes.Any(box => box.PointOfCare == null && box.Bed == location.Bed && box.IsActive))) ||
            section.Items.Any(item =>
                item.Boxes.Any(box =>
                    box.PointOfCare == location.UnitName && box.Bed == location.Bed && box.IsActive))).ToList();
    }

    public async Task<Section?> InsertOneSection(Section section)
    {
        try
        {
            await Collection.InsertOneAsync(section);
            return await FindById(section.Id);
        }
        catch (Exception ex)
        {
            Log.Error("Error inserting section: {section}. Exception: {ex}",
                JsonConvert.SerializeObject(section, Formatting.Indented), ex);

            return null;
        }
    }


    public async Task<Section?> UpdateSection(Section section)
    {
        var filter = Builders<Section>.Filter.Eq("Id", section.Id);
        var update = Builders<Section>.Update
            .Set(c => c.Id, section.Id)
            .Set(c => c.PointOfCare, section.PointOfCare)
            .Set(c => c.SectionTitle, section.SectionTitle)
            .Set(c => c.Configuration, section.Configuration)
            .Set(c => c.Items, section.Items);

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