using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Moq;
using Xunit;

namespace JobTrackerApi.Tests;

public sealed class EmailDraftPersistenceTests
{
    [Fact]
    public async Task Drafts_are_owner_filtered_and_follow_the_owned_job_lifecycle()
    {
        await using var connection = new SqliteConnection("Data Source=:memory:");
        await connection.OpenAsync();
        var options = new DbContextOptionsBuilder<JobTrackerContext>().UseSqlite(connection).Options;

        int userOneJobId;
        int userTwoJobId;
        await using (var seed = Context(options, null))
        {
            await seed.Database.EnsureCreatedAsync();
            var companyOne = new Company { Name = "One", OwnerUserId = "user-1" };
            var companyTwo = new Company { Name = "Two", OwnerUserId = "user-2" };
            seed.Companies.AddRange(companyOne, companyTwo);
            await seed.SaveChangesAsync();
            var jobOne = new JobApplication { JobTitle = "Role one", CompanyId = companyOne.Id, OwnerUserId = "user-1" };
            var jobTwo = new JobApplication { JobTitle = "Role two", CompanyId = companyTwo.Id, OwnerUserId = "user-2" };
            seed.JobApplications.AddRange(jobOne, jobTwo);
            await seed.SaveChangesAsync();
            userOneJobId = jobOne.Id;
            userTwoJobId = jobTwo.Id;
            seed.EmailDrafts.AddRange(
                Draft("user-1", jobOne.Id, "one@example.test"),
                Draft("user-2", jobTwo.Id, "two@example.test"));
            await seed.SaveChangesAsync();
        }

        await using (var userOne = Context(options, "user-1"))
        {
            var visible = Assert.Single(await userOne.EmailDrafts.AsNoTracking().ToListAsync());
            Assert.Equal(userOneJobId, visible.JobApplicationId);
            Assert.Equal("one@example.test", visible.To);
            var job = await userOne.JobApplications.SingleAsync(item => item.Id == userOneJobId);
            userOne.JobApplications.Remove(job);
            await userOne.SaveChangesAsync();
        }

        await using var verify = Context(options, null);
        var remaining = Assert.Single(await verify.EmailDrafts.IgnoreQueryFilters().AsNoTracking().ToListAsync());
        Assert.Equal("user-2", remaining.OwnerUserId);
        Assert.Equal(userTwoJobId, remaining.JobApplicationId);
    }

    private static EmailDraft Draft(string ownerUserId, int jobApplicationId, string recipient) => new()
    {
        Id = Guid.NewGuid(),
        OwnerUserId = ownerUserId,
        JobApplicationId = jobApplicationId,
        Provider = "gmail",
        To = recipient,
        Subject = "Synthetic draft",
        BodyText = "Synthetic private draft body.",
        ThreadId = "thread-1",
        ClientRequestId = Guid.NewGuid().ToString("D"),
        CreatedAtUtc = DateTime.UtcNow,
        UpdatedAtUtc = DateTime.UtcNow,
    };

    private static JobTrackerContext Context(DbContextOptions<JobTrackerContext> options, string? userId)
    {
        var currentUser = new Mock<ICurrentUserService>();
        currentUser.SetupGet(service => service.UserId).Returns(userId);
        return new JobTrackerContext(options, currentUser.Object);
    }
}
