using ErsatzTV.Core.Domain;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Data.Repositories;
using ErsatzTV.Tests.Support;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging.Abstractions;
using NUnit.Framework;
using Shouldly;

namespace ErsatzTV.Tests.Integration;

// ersatztv#460: the disable-sync (remove-and-recreate) flows used to stamp the 0001-01-01 MinValue
// sentinel into Library.LastScan. #409 fixed the READ side (the API coerces the sentinel to null and a
// migration cleaned historical rows), so the wire contract was already correct — these tests pin the
// WRITE side for every provider, so no NEW sentinel rows are created. They do not (and cannot) speak to
// rows already written before this change: those keep the sentinel at rest and are covered only by the
// read-boundary coercion, since this ships no second cleanup migration.
[TestFixture]
public class MediaSourceRepositoryDisableSyncTests
{
    private InMemoryTvContext _db = null!;
    private MediaSourceRepository _repository = null!;

    [SetUp]
    public async Task SetUp()
    {
        _db = await InMemoryTvContext.CreateAsync();
        _repository = new MediaSourceRepository(_db.Factory, NullLogger<MediaSourceRepository>.Instance);
    }

    [TearDown]
    public async Task TearDown() => await _db.DisposeAsync();

    [Test]
    public async Task DisablePlexLibrarySync_Should_Null_LastScan_Not_Write_MinValue()
    {
        int libraryId = await Seed(new PlexLibrary
        {
            Name = "Movies",
            MediaKind = LibraryMediaKind.Movies,
            MediaSourceId = 1,
            Key = "key1",
            ShouldSyncItems = true,
            LastScan = new DateTime(2026, 7, 1, 12, 0, 0, DateTimeKind.Utc),
            Paths = [new LibraryPath { Path = "/data/movies" }]
        });

        await _repository.DisablePlexLibrarySync([libraryId]);

        await using TvContext context = _db.CreateContext();
        PlexLibrary library = await context.PlexLibraries.SingleAsync(l => l.Name == "Movies");
        library.LastScan.ShouldBeNull();
        library.ShouldSyncItems.ShouldBeFalse();
    }

    [Test]
    public async Task DisableJellyfinLibrarySync_Should_Null_LastScan_Not_Write_MinValue()
    {
        int libraryId = await Seed(new JellyfinLibrary
        {
            Name = "Concerts",
            MediaKind = LibraryMediaKind.MusicVideos,
            MediaSourceId = 1,
            ItemId = "item1",
            ShouldSyncItems = true,
            LastScan = new DateTime(2026, 7, 1, 12, 0, 0, DateTimeKind.Utc),
            Paths = [new LibraryPath { Path = "/data/music" }],
            PathInfos = []
        });

        await _repository.DisableJellyfinLibrarySync([libraryId]);

        await using TvContext context = _db.CreateContext();
        JellyfinLibrary library = await context.JellyfinLibraries.SingleAsync(l => l.Name == "Concerts");
        library.LastScan.ShouldBeNull();
        library.ShouldSyncItems.ShouldBeFalse();
    }

    [Test]
    public async Task DisableEmbyLibrarySync_Should_Null_LastScan_Not_Write_MinValue()
    {
        int libraryId = await Seed(new EmbyLibrary
        {
            Name = "Shows",
            MediaKind = LibraryMediaKind.Shows,
            MediaSourceId = 1,
            ItemId = "item1",
            ShouldSyncItems = true,
            LastScan = new DateTime(2026, 7, 1, 12, 0, 0, DateTimeKind.Utc),
            Paths = [new LibraryPath { Path = "/data/shows" }],
            PathInfos = []
        });

        await _repository.DisableEmbyLibrarySync([libraryId]);

        await using TvContext context = _db.CreateContext();
        EmbyLibrary library = await context.EmbyLibraries.SingleAsync(l => l.Name == "Shows");
        library.LastScan.ShouldBeNull();
        library.ShouldSyncItems.ShouldBeFalse();
    }

    private async Task<int> Seed(Library library)
    {
        await using TvContext context = _db.CreateContext();
        await context.AddAsync(library);
        await context.SaveChangesAsync();
        return library.Id;
    }
}
