using System.Security.Claims;
using JobTrackerApi.Controllers;
using JobTrackerApi.Data;
using JobTrackerApi.Models;
using JobTrackerApi.Services;
using JobTrackerApi.Tests.TestSupport;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;

namespace JobTrackerApi.Tests;

public sealed class JobApplicationsFollowUpDraftTests
{
    [Fact]
    public async Task Follow_up_draft_uses_imported_thread_and_saved_package_context()
    {
        await using var db = CreateDb();
        var company = new Company
        {
            Name = "Acme",
            RecruiterName = "Maria Recruiter",
            RecruiterEmail = "maria@acme.test",
            OwnerUserId = "user-1"
        };
        db.Companies.Add(company);
        db.Users.Add(new ApplicationUser
        {
            Id = "user-1",
            UserName = "user@example.test",
            Email = "user@example.test",
            DisplayName = "Casey Candidate"
        });
        await db.SaveChangesAsync();

        var job = new JobApplication
        {
            JobTitle = "Backend Developer",
            CompanyId = company.Id,
            OwnerUserId = "user-1",
            Status = "Waiting",
            DateApplied = new DateTime(2026, 3, 1, 0, 0, 0, DateTimeKind.Utc),
            Description = "Need .NET APIs and clear stakeholder communication.",
            ShortSummary = "Strong overlap in backend API delivery.",
            TailoredCvText = "Saved tailored CV",
            CoverLetterText = "Saved cover letter",
            RecruiterMessageDraft = "Saved recruiter message",
            Notes = "Original notes\n\n<<<APPLICATION_ANSWER_DRAFT>>>\nSaved application answer\n<<<END_APPLICATION_ANSWER_DRAFT>>>"
        };
        db.JobApplications.Add(job);
        await db.SaveChangesAsync();

        db.Correspondences.Add(new Correspondence
        {
            JobApplicationId = job.Id,
            From = "Company",
            Subject = "Backend Developer application update",
            ExternalThreadId = "thread-42",
            ExternalFrom = "Maria Recruiter <maria@acme.test>",
            ExternalTo = "user@example.test",
            Content = "We're aligning interview times and want someone who can own the API layer.",
            Date = new DateTime(2026, 3, 10, 0, 0, 0, DateTimeKind.Utc)
        });
        await db.SaveChangesAsync();

        var summarizer = new Mock<ISummarizerService>();
        summarizer
            .Setup(service => service.SummarizeSectionAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<int>(), It.IsAny<int>()))
            .ReturnsAsync((string instruction, string context, int _, int __) =>
            {
                if (instruction.Contains("List up to 4 concrete application-package signals", StringComparison.OrdinalIgnoreCase))
                {
                    return "Keep the thread moving on interview timing.\nReuse the API-ownership language from the recruiter.";
                }

                if (instruction.Contains("follow-up email", StringComparison.OrdinalIgnoreCase))
                {
                    return context.Contains("Saved cover letter", StringComparison.OrdinalIgnoreCase)
                        && context.Contains("Backend Developer application update", StringComparison.OrdinalIgnoreCase)
                        && context.Contains("Maria Recruiter", StringComparison.OrdinalIgnoreCase)
                        ? "Hi Maria,\n\nI wanted to follow up on the Backend Developer thread and reiterate my fit for owning the API layer.\n\nThanks,\nCasey"
                        : "Generic follow-up";
                }

                return "Generated text";
            });

        var controller = CreateController(db, summarizer.Object, "user-1");
        var result = await controller.GetFollowUpDraft(job.Id, "waiting-update", null, CancellationToken.None);

        var ok = Assert.IsType<OkObjectResult>(result.Result);
        var payload = Assert.IsType<FollowUpDraftDto>(ok.Value);

        Assert.Equal("Re: Backend Developer application update", payload.Subject);
        Assert.Contains("Maria", payload.Body);
        Assert.Contains("Saved application package material is available", payload.ContextSummary);
        Assert.Contains(payload.ContextSignals, item => item.Contains("Saved cover letter available", StringComparison.OrdinalIgnoreCase));
        Assert.Contains(payload.ContextSignals, item => item.Contains("thread participants", StringComparison.OrdinalIgnoreCase));
        Assert.Equal("Backend Developer application update", payload.ThreadSubject);
        Assert.Contains("Maria Recruiter", payload.LastCorrespondenceFrom ?? string.Empty);
    }

    [Fact]
    public void Legacy_follow_up_delivery_is_gone_and_has_no_smtp_dependency()
    {
        using var db = CreateDb();
        var controller = CreateController(db, Mock.Of<ISummarizerService>(), "user-1");

        var result = controller.SendFollowUp(42, new SendFollowUpRequest(
            "recruiter@example.test",
            "Synthetic subject",
            "Synthetic body",
            DateTime.UtcNow.AddDays(3)), default);

        var gone = Assert.IsType<ObjectResult>(result);
        Assert.Equal(StatusCodes.Status410Gone, gone.StatusCode);
        Assert.Equal("Legacy email delivery retired", Assert.IsType<ProblemDetails>(gone.Value).Title);
        Assert.Empty(db.Correspondences);
        Assert.DoesNotContain(typeof(JobApplicationsController).GetConstructors().Single().GetParameters(),
            parameter => parameter.ParameterType == typeof(IAppEmailSender));
    }

    private static JobApplicationsController CreateController(JobTrackerContext db, ISummarizerService summarizer, string userId)
    {
        var controller = new JobApplicationsController(db, summarizer, CreateUserManager().Object);
        controller.ControllerContext = new ControllerContext
        {
            HttpContext = new DefaultHttpContext
            {
                User = new ClaimsPrincipal(new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.NameIdentifier, userId)
                }, "test"))
            }
        };
        return controller;
    }

    private static JobTrackerContext CreateDb()
    {
        return TestHostFactory.CreateInMemoryDb();
    }

    private static Mock<UserManager<ApplicationUser>> CreateUserManager()
    {
        return TestHostFactory.CreateUserManager();
    }
}
