using UniVerse.Application.Mappings;
using UniVerse.Domain.Entities;
using UniVerse.Domain.Enums;
using Xunit;

namespace UniVerse.Api.Tests.Application;

public class MappingExtensionsTests
{
    [Fact]
    public void UserMappings_OrderRolesConsistently()
    {
        var user = new User
        {
            Id = 1,
            Email = "user@test.local",
            DisplayName = "User",
            AvatarUrl = "avatar.png",
            IsActive = true,
            Xp = 120,
            Coins = 30,
            CreatedAt = new DateTime(2026, 1, 2, 3, 4, 5, DateTimeKind.Utc),
            Roles =
            [
                new UserRoleAssignment { Role = UserRole.Teacher },
                new UserRoleAssignment { Role = UserRole.Student },
                new UserRoleAssignment { Role = UserRole.Admin }
            ]
        };

        var dto = user.ToDto(level: 2);
        var currentUser = user.ToCurrentUserDto(level: 2);
        var auth = user.ToAuthDto();

        Assert.Equal(new[] { UserRole.Student, UserRole.Teacher, UserRole.Admin }, dto.Roles);
        Assert.Equal(dto.Roles, currentUser.Roles);
        Assert.Equal(dto.Roles, auth.Roles);
        Assert.Equal(2, dto.Level);
    }

    [Fact]
    public void LectureMappings_UseNavigationFallbacksAndEnrollmentCount()
    {
        var startsAt = new DateTime(2026, 2, 1, 9, 0, 0, DateTimeKind.Utc);
        var lecture = new Lecture
        {
            Id = 10,
            CourseId = 5,
            Title = "Offline lecture",
            Description = "Description",
            Format = LectureFormat.Offline,
            StartsAt = startsAt,
            EndsAt = startsAt.AddHours(2),
            IsOpen = true,
            MaxEnrollments = 25,
            MandatoryAttendeesCount = 30,
            Enrollments =
            [
                new LectureEnrollment { UserId = 1 },
                new LectureEnrollment { UserId = 2 }
            ]
        };

        var dto = lecture.ToDto(isEnrolled: true);
        var detail = lecture.ToDetailDto(isEnrolled: false);

        Assert.Equal("", dto.CourseName);
        Assert.Null(dto.TeacherName);
        Assert.Null(dto.LocationName);
        Assert.Equal(32, dto.EnrollmentsCount);
        Assert.True(dto.IsEnrolled);
        Assert.False(detail.IsEnrolled);
    }

    [Fact]
    public void ReviewMapping_CopiesAnalysisFields()
    {
        var review = new Review
        {
            Id = 7,
            LectureId = 3,
            UserId = 4,
            Rating = ReviewRating.Like,
            Text = "Clear and useful",
            LlmStatus = ReviewLlmStatus.Analyzed,
            Sentiment = ReviewSentiment.Positive,
            QualityScore = 0.95,
            IsInformative = true,
            LlmTags = ["clear", "useful"],
            LlmRawOutput = "{\"quality_score\":0.95}",
            CreatedAt = new DateTime(2026, 3, 4, 5, 6, 7, DateTimeKind.Utc),
            Lecture = new Lecture { Title = "Lecture title" },
            User = new User { DisplayName = "Student" }
        };

        var dto = review.ToDto();

        Assert.Equal("Lecture title", dto.LectureTitle);
        Assert.Equal("Student", dto.UserName);
        Assert.Equal(ReviewSentiment.Positive, dto.Sentiment);
        Assert.Equal(0.95, dto.QualityScore);
        Assert.True(dto.IsInformative);
        Assert.NotNull(dto.LlmTags);
        Assert.Equal(["clear", "useful"], dto.LlmTags);
        Assert.Equal("{\"quality_score\":0.95}", dto.LlmRawOutput);
    }

    [Fact]
    public void TagTreeMapping_MapsChildrenRecursively()
    {
        var root = new Tag { Id = 1, Name = "Root", Type = TagType.Topic };
        var child = new Tag { Id = 2, Name = "Child", Type = TagType.Subject, ParentId = 1 };
        var grandchild = new Tag { Id = 3, Name = "Grandchild", Type = TagType.Other, ParentId = 2 };
        root.Children.Add(child);
        child.Children.Add(grandchild);

        var dto = root.ToTreeDto();

        Assert.Equal("Root", dto.Name);
        var childDto = Assert.Single(dto.Children);
        Assert.Equal("Child", childDto.Name);
        Assert.Equal("Grandchild", Assert.Single(childDto.Children).Name);
    }
}
