using UniVerse.Application.DTOs.Achievements;
using UniVerse.Application.DTOs.Auth;
using UniVerse.Application.DTOs.Courses;
using UniVerse.Application.DTOs.Gamification;
using UniVerse.Application.DTOs.Lectures;
using UniVerse.Application.DTOs.Locations;
using UniVerse.Application.DTOs.Reviews;
using UniVerse.Application.DTOs.Tags;
using UniVerse.Application.DTOs.Users;
using UniVerse.Domain.Entities;

namespace UniVerse.Application.Mappings;

public static class MappingExtensions
{
    private static int OccupiedSeatsCount(this Lecture lecture) =>
        Math.Max(0, lecture.MandatoryAttendeesCount) + lecture.Enrollments.Count;

    // --- User ---
    public static UserDto ToDto(this User user, int level) => new(
        user.Id, user.Email, user.DisplayName, user.AvatarUrl,
        user.Roles.Select(r => r.Role).OrderBy(r => r).ToList(), user.IsActive, user.Xp, user.Coins, level, user.CreatedAt
    );

    public static CurrentUserDto ToCurrentUserDto(this User user, int level) => new(
        user.Id, user.Email, user.DisplayName, user.AvatarUrl,
        user.Roles.Select(r => r.Role).OrderBy(r => r).ToList(), user.Xp, user.Coins, level, user.CreatedAt
    );

    public static UserAuthDto ToAuthDto(this User user) => new(
        user.Id, user.Email, user.DisplayName, user.Roles.Select(r => r.Role).OrderBy(r => r).ToList()
    );

    // --- Tag ---
    public static TagDto ToDto(this Tag tag) => new(
        tag.Id, tag.Name, tag.Type, tag.ParentId, tag.CreatedAt
    );

    public static TagTreeDto ToTreeDto(this Tag tag) => new(
        tag.Id, tag.Name, tag.Type,
        tag.Children.Select(c => c.ToTreeDto()).ToList()
    );

    // --- Location ---
    public static LocationDto ToDto(this Location loc) => new(
        loc.Id, loc.Name, loc.Building, loc.Room, loc.Address, loc.CreatedAt
    );

    // --- Course ---
    public static CourseDto ToDto(this Course course) => new(
        course.Id, course.Name, course.Description, course.IsSynced,
        course.CourseTags.Select(ct => ct.Tag.ToDto()).ToList(),
        course.CreatedAt
    );

    // --- Lecture ---
    public static LectureDto ToDto(this Lecture lecture, bool isEnrolled = false) => new(
        lecture.Id, lecture.CourseId, lecture.Course?.Name ?? "",
        lecture.TeacherId, lecture.Teacher?.DisplayName,
        lecture.LocationId, lecture.Location?.Name,
        lecture.Title, lecture.Description, lecture.Format,
        lecture.StartsAt, lecture.EndsAt, lecture.IsOpen,
        lecture.MaxEnrollments, lecture.OccupiedSeatsCount(),
        lecture.OnlineUrl, lecture.CreatedAt, isEnrolled
    );

    public static LectureDetailDto ToDetailDto(this Lecture lecture, bool isEnrolled) => new(
        lecture.Id, lecture.CourseId, lecture.Course?.Name ?? "",
        lecture.TeacherId, lecture.Teacher?.DisplayName,
        lecture.LocationId, lecture.Location?.Name,
        lecture.Title, lecture.Description, lecture.Format,
        lecture.StartsAt, lecture.EndsAt, lecture.IsOpen,
        lecture.MaxEnrollments, lecture.OccupiedSeatsCount(),
        lecture.OnlineUrl, lecture.CreatedAt, isEnrolled
    );

    // --- Enrollment ---
    public static EnrollmentDto ToDto(this LectureEnrollment enrollment) => new(
        enrollment.Id, enrollment.UserId,
        enrollment.User?.DisplayName, enrollment.User?.Email,
        enrollment.Attended, enrollment.CreatedAt
    );

    // --- Review ---
    public static ReviewDto ToDto(this Review review) => new(
        review.Id, review.LectureId, review.Lecture?.Title,
        review.UserId, review.User?.DisplayName,
        review.Rating, review.Text, review.LlmStatus,
        review.Sentiment, review.QualityScore, review.IsInformative,
        review.LlmTags, review.LlmRawOutput, review.CreatedAt
    );

    // --- Achievement ---
    public static AchievementDto ToDto(this Achievement a) => new(
        a.Id, a.Name, a.Description, a.IconUrl, a.XpReward, a.CoinReward, a.Condition, a.CreatedAt
    );

    public static UserAchievementDto ToDto(this UserAchievement ua) => new(
        ua.Id, ua.Achievement.ToDto(), ua.AwardedAt
    );

    // --- CoinTransaction ---
    public static CoinTransactionDto ToDto(this CoinTransaction ct) => new(
        ct.Id, ct.Amount, ct.Type, ct.ReviewId, ct.AchievementId, ct.Description, ct.CreatedAt
    );
}
