using adas_core.Domain.Models;
using adas_core.Domain.Models.AppSettings;
using adas_core.Infrastructure.Repositories;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using MongoDB.Driver;
using Options = Microsoft.Extensions.Options.Options;

namespace adas_core.Test.Repositories;

[TestFixture]
[Category("Integration")]
public class RecordingAlertRepositoryTest
{
    [OneTimeSetUp]
    public async Task Init()
    {
        _optionsApiSettings = Options.Create(_apiSettings);

        var recordingAlert1 = new PatientRecordingAlert
        {
            PatientId = PatientId,
            IsRecording = true,
            Time = Now
        };

        var recordingAlert2 = new PatientRecordingAlert
        {
            PatientId = ObjectId.GenerateNewId(),
            IsRecording = true,
            Time = Now.AddDays(-10)
        };

        await IntegrationDb.Database.DropCollectionAsync("archive_patients_recordingalerts");
        await IntegrationDb.Database.CreateCollectionAsync("archive_patients_recordingalerts");

        _repository = new RecordingAlertRepository(_optionsApiSettings, IntegrationDb.Database);

        await _repository.InsertOneAsync(recordingAlert1);
        await _repository.InsertOneAsync(recordingAlert2);

        Assert.That(await _repository.Collection.CountDocumentsAsync(_ => true), Is.EqualTo(2));
    }

    private RecordingAlertRepository _repository;

    private readonly ApiSettings _apiSettings = new()
    {
        ArchivePatientsRecordingalerts = "archive_patients_recordingalerts"
    };

    private IOptions<ApiSettings> _optionsApiSettings;

    private static readonly DateTime Now = DateTime.Now;
    private static readonly ObjectId PatientId = ObjectId.GenerateNewId();


    [Test]
    public async Task DeleteAsync()
    {
        var recordingAlert = new PatientRecordingAlert
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = ObjectId.GenerateNewId(),
            IsRecording = true,
            Time = Now
        };

        await _repository.InsertOneAsync(recordingAlert);

        var result = await _repository.Collection.FindAsync(p => p.Id == recordingAlert.Id);

        Assert.That(result.FirstOrDefault(), Is.Not.Null);

        await _repository.DeleteAsync(recordingAlert.Id);

        var resultDelete = await _repository.Collection.FindAsync(p => p.Id == recordingAlert.Id);

        Assert.That(resultDelete.FirstOrDefault(), Is.Null);
    }


    [Test]
    public async Task DeleteOlderDaysAsync()
    {
        var recordingAlert = new PatientRecordingAlert
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = ObjectId.GenerateNewId(),
            IsRecording = true,
            Time = Now,
            Name = "recordingName1"
        };

        var recordingAlertOld = new PatientRecordingAlert
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = recordingAlert.PatientId,
            IsRecording = true,
            Time = Now.AddDays(-5),
            Name = "recordingName1"
        };

        await _repository.InsertOneAsync(recordingAlert);
        await _repository.InsertOneAsync(recordingAlertOld);

        var result = await _repository.Collection.FindAsync(p => p.PatientId == recordingAlert.PatientId);

        Assert.That(result.ToList(), Has.Count.EqualTo(2));

        await _repository.DeleteOlderDaysAsync("recordingName1", 2);

        var resultDelete = await _repository.Collection.FindAsync(p => p.PatientId == recordingAlert.PatientId);

        Assert.That(resultDelete.ToList(), Has.Count.EqualTo(1));

        await _repository.Collection.DeleteManyAsync(d => d.PatientId == recordingAlert.PatientId);

        var resultClear = await _repository.Collection.FindAsync(p => p.PatientId == recordingAlert.PatientId);

        Assert.That(resultClear.ToList(), Has.Count.EqualTo(0));
    }

    [Test]
    public async Task DeleteOlderNumberAsync()
    {
        var recordingAlert = new PatientRecordingAlert
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = ObjectId.GenerateNewId(),
            IsRecording = true,
            Time = Now,
            Name = "recordingName1"
        };

        var recordingAlertOld = new PatientRecordingAlert
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = recordingAlert.PatientId,
            IsRecording = true,
            Time = Now.AddDays(-5),
            Name = "recordingName1"
        };

        await _repository.InsertOneAsync(recordingAlert);
        await _repository.InsertOneAsync(recordingAlertOld);

        var result = await _repository.Collection.FindAsync(p => p.Name == "recordingName1");

        Assert.That(result.ToList(), Has.Count.EqualTo(2));

        await _repository.DeleteOlderNumberAsync("recordingName1", 1);

        var resultDelete = await _repository.Collection.FindAsync(p => p.Name == "recordingName1");

        Assert.That(resultDelete.ToList(), Has.Count.EqualTo(1));
    }

    [Test]
    public async Task DeleteByPatientId()
    {
        var recordingAlert = new PatientRecordingAlert
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = ObjectId.GenerateNewId(),
            IsRecording = true,
            Time = Now
        };

        var recordingAlertOld = new PatientRecordingAlert
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = recordingAlert.PatientId,
            IsRecording = true,
            Time = Now.AddDays(-5)
        };

        await _repository.InsertOneAsync(recordingAlert);
        await _repository.InsertOneAsync(recordingAlertOld);

        var result = await _repository.Collection.FindAsync(p => p.PatientId == recordingAlert.PatientId);

        Assert.That(result.FirstOrDefault(), Is.Not.Null);

        await _repository.DeleteByPatientId(recordingAlert.PatientId);

        var resultDelete = await _repository.Collection.FindAsync(p => p.PatientId == recordingAlert.PatientId);

        Assert.That(resultDelete.FirstOrDefault(), Is.Null);
    }

    [Test]
    public async Task FindByPatientIdAsync()
    {
        var result = await _repository.FindByPatientIdAsync(PatientId);

        Assert.That(result.FirstOrDefault(), Is.Not.Null);
    }

    [Test]
    public async Task FindLastObservations()
    {
        var recordingAlert = new PatientRecordingAlert
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = ObjectId.GenerateNewId(),
            IsRecording = true,
            Time = Now,
            Name = "recordingName1"
        };

        var recordingAlertOld = new PatientRecordingAlert
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = recordingAlert.PatientId,
            IsRecording = true,
            Time = Now.AddDays(-5),
            Name = "recordingName1"
        };

        await _repository.InsertOneAsync(recordingAlert);
        await _repository.InsertOneAsync(recordingAlertOld);

        var result = await _repository.Collection.FindAsync(_ => true);

        Assert.That(result, Is.Not.Null);
        Assert.That(result.ToList(), Has.Count.GreaterThan(2));

        var resultFind = await _repository.FindLastObservations(recordingAlert.PatientId, "recordingName1", 1);

        Assert.That(resultFind, Is.Not.Null);
        using (Assert.EnterMultipleScope())
        {
            Assert.That(resultFind.ToList(), Has.Count.EqualTo(1));
            Assert.That(resultFind.FirstOrDefault()?.Time.Day, Is.EqualTo(Now.Day));
            Assert.That(resultFind.FirstOrDefault()?.Time.Month, Is.EqualTo(Now.Month));
            Assert.That(resultFind.FirstOrDefault()?.Time.Year, Is.EqualTo(Now.Year));
        };
        await _repository.DeleteByPatientId(recordingAlert.PatientId);

        var resultDelete = await _repository.Collection.FindAsync(p => p.PatientId == recordingAlert.PatientId);

        Assert.That(resultDelete.FirstOrDefault(), Is.Null);
    }

    [Test]
    public async Task UpdateManyObjectId()
    {
        var recordingAlert = new PatientRecordingAlert
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = ObjectId.GenerateNewId(),
            IsRecording = true,
            Time = Now
        };

        var newPatientId = ObjectId.GenerateNewId();

        await _repository.InsertOneAsync(recordingAlert);

        var result = await _repository.FindByPatientIdAsync(recordingAlert.PatientId);

        Assert.That(result.FirstOrDefault(), Is.Not.Null);

        await _repository.UpdateManyObjectId("patientid", newPatientId, recordingAlert.PatientId);

        var resultOldId = await _repository.FindByPatientIdAsync(recordingAlert.PatientId);

        Assert.That(resultOldId.FirstOrDefault(), Is.Null);

        var resultNewId = await _repository.FindByPatientIdAsync(newPatientId);

        Assert.That(resultNewId.FirstOrDefault(), Is.Not.Null);

        await _repository.DeleteByPatientId(newPatientId);

        var resultDelete = await _repository.FindByPatientIdAsync(newPatientId);

        Assert.That(resultDelete.FirstOrDefault(), Is.Null);
    }
}