using FluentAssertions;
using RealCV.Application.Models;
using RealCV.Infrastructure.Services;

namespace RealCV.Tests.Services;

public sealed class EducationVerifierServiceTests
{
    private readonly EducationVerifierService _sut = new();

    #region Diploma Mill Detection

    [Theory]
    [InlineData("Belford University")]
    [InlineData("Ashwood University")]
    [InlineData("Rochville University")]
    [InlineData("St Regis University")]
    public void Verify_DiplomaMillInstitution_ReturnsDiplomaMill(string institution)
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = institution,
            Qualification = "PhD",
            Subject = "Business",
            StartDate = new DateOnly(2020, 1, 1),
            EndDate = new DateOnly(2020, 6, 1)
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.Status.Should().Be("DiplomaMill");
        result.IsDiplomaMill.Should().BeTrue();
        result.IsSuspicious.Should().BeTrue();
        result.IsVerified.Should().BeFalse();
    }

    [Fact]
    public void Verify_DiplomaMillInstitution_IncludesVerificationNotes()
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = "Belford University",
            Qualification = "MBA"
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.VerificationNotes.Should().Contain("not found in accredited institutions");
    }

    #endregion

    #region Suspicious Pattern Detection

    [Theory]
    [InlineData("Global Online University")]
    [InlineData("Premier University of Excellence")]
    [InlineData("Executive Virtual University")]
    public void Verify_SuspiciousPatternInstitution_ReturnsSuspicious(string institution)
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = institution
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.Status.Should().Be("Suspicious");
        result.IsSuspicious.Should().BeTrue();
        result.IsDiplomaMill.Should().BeFalse();
        result.IsVerified.Should().BeFalse();
    }

    #endregion

    #region UK Institution Recognition

    [Theory]
    [InlineData("University of Cambridge", "University of Cambridge")]
    [InlineData("Cambridge", "University of Cambridge")]
    [InlineData("University of Oxford", "University of Oxford")]
    [InlineData("Oxford", "University of Oxford")]
    [InlineData("Imperial College London", "Imperial College London")]
    [InlineData("UCL", "UCL")]  // UCL is directly in the recognised list
    [InlineData("LSE", "LSE")]  // LSE is directly in the recognised list
    public void Verify_RecognisedUKInstitution_ReturnsRecognised(string input, string expectedMatch)
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = input,
            Qualification = "BSc",
            StartDate = new DateOnly(2018, 9, 1),
            EndDate = new DateOnly(2021, 6, 1)
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.Status.Should().Be("Recognised");
        result.IsVerified.Should().BeTrue();
        result.IsDiplomaMill.Should().BeFalse();
        result.IsSuspicious.Should().BeFalse();
        result.MatchedInstitution.Should().Be(expectedMatch);
    }

    [Fact]
    public void Verify_RecognisedInstitution_IncludesVerificationNotes()
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = "University of Manchester"
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.VerificationNotes.Should().Contain("Verified UK higher education institution");
    }

    [Fact]
    public void Verify_RecognisedInstitutionVariation_NotesMatchedName()
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = "Cambridge"
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.VerificationNotes.Should().Contain("Matched to official name");
        result.MatchedInstitution.Should().Be("University of Cambridge");
    }

    #endregion

    #region Unknown Institutions

    [Fact]
    public void Verify_UnknownInstitution_ReturnsUnknown()
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = "University of Ljubljana",
            Qualification = "BSc"
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.Status.Should().Be("Unknown");
        result.IsVerified.Should().BeFalse();
        result.IsDiplomaMill.Should().BeFalse();
        result.IsSuspicious.Should().BeFalse();
        result.VerificationNotes.Should().Contain("international institution");
    }

    #endregion

    #region Date Plausibility

    [Fact]
    public void Verify_PlausibleDates_ReturnsPlausible()
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = "University of Bristol",
            StartDate = new DateOnly(2018, 9, 1),
            EndDate = new DateOnly(2021, 6, 1)
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.DatesArePlausible.Should().BeTrue();
        result.DatePlausibilityNotes.Should().BeNull();
    }

    [Fact]
    public void Verify_TooShortCourseDuration_ReturnsImplausible()
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = "University of Bristol",
            StartDate = new DateOnly(2020, 1, 1),
            EndDate = new DateOnly(2020, 6, 1) // 6 months
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.DatesArePlausible.Should().BeFalse();
        result.DatePlausibilityNotes.Should().Contain("unusually short");
    }

    [Fact]
    public void Verify_TooLongCourseDuration_ReturnsImplausible()
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = "University of Bristol",
            StartDate = new DateOnly(2010, 1, 1),
            EndDate = new DateOnly(2020, 1, 1) // 10 years
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.DatesArePlausible.Should().BeFalse();
        result.DatePlausibilityNotes.Should().Contain("unusually long");
    }

    [Fact]
    public void Verify_EndDateBeforeStartDate_ReturnsImplausible()
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = "University of Bristol",
            StartDate = new DateOnly(2021, 1, 1),
            EndDate = new DateOnly(2020, 1, 1)
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.DatesArePlausible.Should().BeFalse();
        result.DatePlausibilityNotes.Should().Contain("before or equal to start date");
    }

    [Fact]
    public void Verify_NoDates_AssumesPlausible()
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = "University of Bristol"
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.DatesArePlausible.Should().BeTrue();
    }

    #endregion

    #region VerifyAll

    [Fact]
    public void VerifyAll_MultipleEducations_ReturnsResultsForEach()
    {
        // Arrange
        var educations = new List<EducationEntry>
        {
            new() { Institution = "University of Cambridge" },
            new() { Institution = "Belford University" },
            new() { Institution = "Unknown Foreign University" }
        };

        // Act
        var results = _sut.VerifyAll(educations);

        // Assert
        results.Should().HaveCount(3);
        results[0].Status.Should().Be("Recognised");
        results[1].Status.Should().Be("DiplomaMill");
        results[2].Status.Should().Be("Unknown");
    }

    [Fact]
    public void VerifyAll_OverlappingEducation_NotesOverlap()
    {
        // Arrange
        var educations = new List<EducationEntry>
        {
            new()
            {
                Institution = "University of Bristol",
                StartDate = new DateOnly(2018, 9, 1),
                EndDate = new DateOnly(2021, 6, 1)
            },
            new()
            {
                Institution = "University of Bath",
                StartDate = new DateOnly(2020, 9, 1),
                EndDate = new DateOnly(2023, 6, 1)
            }
        };

        // Act
        var results = _sut.VerifyAll(educations);

        // Assert
        results[0].DatePlausibilityNotes.Should().Contain("Overlaps with");
        results[1].DatePlausibilityNotes.Should().Contain("Overlaps with");
    }

    [Fact]
    public void VerifyAll_EmploymentBeforeGraduation_ChecksTimeline()
    {
        // Arrange
        var educations = new List<EducationEntry>
        {
            new()
            {
                Institution = "University of Bristol",
                StartDate = new DateOnly(2018, 9, 1),
                EndDate = new DateOnly(2021, 6, 1)
            }
        };

        var employment = new List<EmploymentEntry>
        {
            new()
            {
                CompanyName = "Tech Corp",
                JobTitle = "Senior Developer",
                StartDate = new DateOnly(2018, 1, 1) // Started before education started
            }
        };

        // Act
        var results = _sut.VerifyAll(educations, employment);

        // Assert
        results[0].DatesArePlausible.Should().BeFalse();
        results[0].DatePlausibilityNotes.Should().Contain("months before claimed graduation");
    }

    [Fact]
    public void VerifyAll_InternshipBeforeGraduation_AllowsTimeline()
    {
        // Arrange
        var educations = new List<EducationEntry>
        {
            new()
            {
                Institution = "University of Bristol",
                StartDate = new DateOnly(2018, 9, 1),
                EndDate = new DateOnly(2021, 6, 1)
            }
        };

        var employment = new List<EmploymentEntry>
        {
            new()
            {
                CompanyName = "Tech Corp",
                JobTitle = "Software Intern",
                StartDate = new DateOnly(2019, 6, 1)
            }
        };

        // Act
        var results = _sut.VerifyAll(educations, employment);

        // Assert
        // Should be plausible because it's an internship
        results[0].DatesArePlausible.Should().BeTrue();
    }

    #endregion

    #region Data Preservation

    [Fact]
    public void Verify_PreservesAllClaimedData()
    {
        // Arrange
        var education = new EducationEntry
        {
            Institution = "University of Bristol",
            Qualification = "BSc Computer Science",
            Subject = "Computer Science",
            Grade = "First Class Honours",
            StartDate = new DateOnly(2018, 9, 1),
            EndDate = new DateOnly(2021, 6, 1)
        };

        // Act
        var result = _sut.Verify(education);

        // Assert
        result.ClaimedInstitution.Should().Be("University of Bristol");
        result.ClaimedQualification.Should().Be("BSc Computer Science");
        result.ClaimedSubject.Should().Be("Computer Science");
        result.ClaimedStartDate.Should().Be(new DateOnly(2018, 9, 1));
        result.ClaimedEndDate.Should().Be(new DateOnly(2021, 6, 1));
    }

    #endregion
}
