using adas_core.Application.Repositories.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.Pumps;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;

namespace adas_core.Infrastructure.Repositories;

public class PumpAlarmStateRepository : MongoRepository<PumpAlarmState>, IPumpAlarmStateRepository
{
    private readonly ApiSettings _apiSettings;

    public PumpAlarmStateRepository(IOptions<ApiSettings> apiSettings, IMongoDatabase database)
        : base(database)
    {
        _apiSettings = apiSettings.Value;
    }

  

    public override string GetCollectionName()
    {
        return _apiSettings.PumpAlarmState ?? "pump_alarm_state";
    }

    public override async Task CreateIndexes()
    {
        var indexModels = new List<CreateIndexModel<PumpAlarmState>>
        {
            // Clave única de alarma activa
            new(
                Builders<PumpAlarmState>.IndexKeys
                    .Ascending(x => x.DeviceId)
                    .Ascending(x => x.AlarmType)
                    .Ascending(x => x.AlarmCodeMdc),
                new CreateIndexOptions { Unique = true, Name = "ux_device_alarm" }),

            // Indexado por DeviceId
            new(
                Builders<PumpAlarmState>.IndexKeys.Ascending(x => x.DeviceId),
                new CreateIndexOptions { Name = "ix_device" }),

            // indexado por PatientId
            new(
                Builders<PumpAlarmState>.IndexKeys.Ascending(x => x.PatientId),
                new CreateIndexOptions { Name = "ix_patientId" })
        };

        await Collection.Indexes.CreateManyAsync(indexModels);
    }

    public async Task<PumpAlarmState?> FindActiveAsync(string deviceId, PumpEnum.AlarmType? alarmType, string? alarmCodeMdc = null)
    {
        var filter = Builders<PumpAlarmState>.Filter.Eq(x => x.DeviceId, deviceId);

        if (alarmType.HasValue)
            filter &= Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmType, alarmType);

        if (!string.IsNullOrWhiteSpace(alarmCodeMdc))
            filter &= Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmCodeMdc, alarmCodeMdc);

        return await Collection.Find(filter).FirstOrDefaultAsync();
    }

    public async Task UpsertActiveAsync(PumpAlarmState state)
    {
        var filter =
            Builders<PumpAlarmState>.Filter.Eq(x => x.DeviceId, state.DeviceId) &
            Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmType, state.AlarmType) &
            Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmCodeMdc, state.AlarmCodeMdc);

        // Revisar si ya existe un documento activo con esa combinación
        var existing = await Collection.Find(filter).FirstOrDefaultAsync();

        if (existing != null)
            state.Id = existing.Id;
        else
            if (state.Id == ObjectId.Empty)
                state.Id = ObjectId.GenerateNewId();

        await Collection.ReplaceOneAsync(
            filter,
            state,
            new ReplaceOptions { IsUpsert = true });
    }


    public async Task RemoveAsync(string? deviceId, PumpEnum.AlarmType? alarmType, string? alarmCodeMdc = null)
    {
        var filter = Builders<PumpAlarmState>.Filter.Eq(x => x.DeviceId, deviceId);

        if (alarmType.HasValue)
            filter &= Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmType, alarmType);

        if (!string.IsNullOrWhiteSpace(alarmCodeMdc))
            filter &= Builders<PumpAlarmState>.Filter.Eq(x => x.AlarmCodeMdc, alarmCodeMdc);

        await Collection.DeleteManyAsync(filter);
    }

    public async Task DeleteByPatientId(ObjectId patientId)
    {
        await Collection.DeleteManyAsync(p => p.PatientId == patientId);
    }

    public async Task<IEnumerable<PumpAlarmState>> FindAllActiveByDeviceAsync(string deviceId)
    {
        return await Collection.Find(x => x.DeviceId == deviceId).ToListAsync();
    }
        
    public async Task<long> UpdateManyObjectIdByFieldNameAsync(string fieldName, ObjectId newId, ObjectId oldId)
    {
        var filter = Builders<PumpAlarmState>.Filter.Eq(fieldName, oldId);
        var update = Builders<PumpAlarmState>.Update.Set(fieldName, newId);
        var result = await Collection.UpdateManyAsync(filter, update);
        return result.ModifiedCount;
    }
}