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.EntityFrameworkCore;
using Microsoft.Extensions.Logging.Abstractions;
using Moq;
using Xunit;

namespace JobTrackerApi.Tests;

public sealed class JobApplicationsWorkflowSignalsTests
{
    [Fact]
    public async Task Readiness_keeps_package_gap_when_notes_do_not_contain_saved_answer_block()
    {
        await using var db = CreateDb();
        var company = new Company { Name = "Acme", OwnerUserId = "user-1" };
        db.Companies.Add(company);
        await db.SaveChangesAsync();

        var job = new JobApplication
        {
            JobTitle = "Backend Developer",
            CompanyId = company.Id,
            OwnerUserId = "user-1",
            Status = "Applied",
            DateApplied = DateTime.UtcNow,
            TailoredCvText = "Saved tailored CV",
            Notes = "Interview talking points and recruiter notes without any saved application-answer markers.",
            HasPortfolio = true,
            NextAction = "Wait for recruiter reply"
        };
        db.JobApplications.Add(job);
        await db.SaveChangesAsync();

        var controller = CreateController(db, "user-1");
        var result = await controller.GetReadiness(job.Id, CancellationToken.None);

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

        Assert.Equal("package-work", payload.WorkflowSignal.ActionKey);
        Assert.True(payload.WorkflowSignal.HasPackageGap);
        Assert.True(payload.WorkflowSignal.HasTailoredCv);
        Assert.False(payload.WorkflowSignal.HasSavedApplicationAnswerDraft);
        Assert.Contains(payload.Missing, item => item.Contains("Save application answers", StringComparison.OrdinalIgnoreCase));
        Assert.DoesNotContain(payload.Reminders, item => item.Contains("tailored cv and saved application answers", StringComparison.OrdinalIgnoreCase) && item.Contains("notes", StringComparison.OrdinalIgnoreCase));
    }

    [Fact]
    public async Task Reminders_return_normalized_workflow_routes_for_package_and_follow_up_actions()
    {
        await using var db = CreateDb();
        var company = new Company { Name = "Acme", OwnerUserId = "user-1" };
        db.Companies.Add(company);
        await db.SaveChangesAsync();

        var packageGapJob = new JobApplication
        {
            JobTitle = "Platform Engineer",
            CompanyId = company.Id,
            OwnerUserId = "user-1",
            Status = "Waiting",
            DateApplied = DateTime.UtcNow.AddDays(-20),
            Notes = "General notes only",
            TailoredCvText = null,
            ResponseReceived = false
        };

        var followUpJob = new JobApplication
        {
            JobTitle = "API Engineer",
            CompanyId = company.Id,
            OwnerUserId = "user-1",
            Status = "Waiting",
            DateApplied = DateTime.UtcNow.AddDays(-20),
            TailoredCvText = "Saved tailored CV",
            Notes = "Prep notes\n\n<<<APPLICATION_ANSWER_DRAFT>>>\nSaved answer\n<<<END_APPLICATION_ANSWER_DRAFT>>>",
            ResponseReceived = false
        };

        db.JobApplications.AddRange(packageGapJob, followUpJob);
        await db.SaveChangesAsync();

        var controller = CreateController(db, "user-1");
        var result = await controller.GetReminders(14, CancellationToken.None);

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

        var packageReminder = Assert.Single(payload, item => item.Id == packageGapJob.Id);
        Assert.Equal("package-work", packageReminder.WorkflowSignal.ActionKey);
        Assert.Equal("tailored-cv", packageReminder.WorkflowSignal.WorkspaceTab);
        Assert.Equal(packageReminder.WorkflowSignal.Reason, packageReminder.FollowUpReason);
        Assert.True(packageReminder.WorkflowSignal.HasPackageGap);

        var followUpReminder = Assert.Single(payload, item => item.Id == followUpJob.Id);
        Assert.Equal("follow-up", followUpReminder.WorkflowSignal.ActionKey);
        Assert.Equal("follow-up", followUpReminder.WorkflowSignal.WorkspaceTab);
        Assert.Equal("waiting-update", followUpReminder.WorkflowSignal.FollowMode);
        Assert.Equal(followUpReminder.WorkflowSignal.Reason, followUpReminder.FollowUpReason);
        Assert.True(followUpReminder.WorkflowSignal.NeedsFollowUpAction);
    }

    private static JobApplicationsController CreateController(JobTrackerContext db, string userId)
    {
        var controller = new JobApplicationsController(db, Mock.Of<ISummarizerService>(), 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();
    }
}
