namespace MissionService.Domain.AggregatesModel.RewardAggregate;

using MissionService.Domain.SeedWork;

/// <summary>
/// EN: User reward aggregate root - tracks rewards earned by user
/// VI: UserReward aggregate root - theo dõi phần thưởng user nhận được
/// </summary>
public class UserReward : Entity, IAggregateRoot
{
    /// <summary>EN: User ID / VI: ID người dùng</summary>
    public Guid UserId { get; private set; }
    
    /// <summary>EN: Source ID (TaskId or CheckInId) / VI: ID nguồn (TaskId hoặc CheckInId)</summary>
    public Guid SourceId { get; private set; }
    
    /// <summary>EN: Type of reward / VI: Loại phần thưởng</summary>
    public RewardType Type { get; private set; }
    
    /// <summary>EN: Current status / VI: Trạng thái hiện tại</summary>
    public RewardStatus Status { get; private set; }
    
    /// <summary>EN: Reward amount / VI: Số lượng phần thưởng</summary>
    public RewardAmount Amount { get; private set; } = null!;
    
    /// <summary>EN: When reward was earned / VI: Thời điểm nhận thưởng</summary>
    public DateTime EarnedAt { get; private set; }
    
    /// <summary>EN: When reward was claimed / VI: Thời điểm claim thưởng</summary>
    public DateTime? ClaimedAt { get; private set; }
    
    /// <summary>EN: When reward expires / VI: Thời điểm hết hạn</summary>
    public DateTime? ExpiresAt { get; private set; }
    
    // EF Core constructor
    protected UserReward() { }
    
    private UserReward(
        Guid userId,
        Guid sourceId,
        RewardType type,
        RewardAmount amount,
        DateTime? expiresAt)
    {
        UserId = userId;
        SourceId = sourceId;
        Type = type;
        Status = RewardStatus.Pending;
        Amount = amount;
        EarnedAt = DateTime.UtcNow;
        ExpiresAt = expiresAt;
    }
    
    /// <summary>
    /// EN: Create reward for mission completion / VI: Tạo thưởng cho hoàn thành mission
    /// </summary>
    public static UserReward ForMission(Guid userId, Guid taskId, decimal points, DateTime? expiresAt = null)
    {
        return new UserReward(
            userId,
            taskId,
            RewardType.MissionComplete,
            RewardAmount.Create(points),
            expiresAt);
    }
    
    /// <summary>
    /// EN: Create reward for daily check-in / VI: Tạo thưởng cho điểm danh hàng ngày
    /// </summary>
    public static UserReward ForCheckIn(Guid userId, Guid checkInId, decimal basePoints, decimal bonusPoints)
    {
        return new UserReward(
            userId,
            checkInId,
            RewardType.CheckInDaily,
            RewardAmount.Create(basePoints, bonusPoints),
            null);
    }
    
    /// <summary>
    /// EN: Create milestone reward / VI: Tạo thưởng mốc
    /// </summary>
    public static UserReward ForMilestone(Guid userId, Guid checkInId, decimal points)
    {
        return new UserReward(
            userId,
            checkInId,
            RewardType.CheckInMilestone,
            RewardAmount.Create(points),
            null);
    }
    
    /// <summary>
    /// EN: Create referral bonus / VI: Tạo thưởng giới thiệu
    /// </summary>
    public static UserReward ForReferral(Guid userId, Guid referralId, decimal points)
    {
        return new UserReward(
            userId,
            referralId,
            RewardType.ReferralBonus,
            RewardAmount.Create(points),
            null);
    }
    
    /// <summary>
    /// EN: Claim the reward / VI: Nhận thưởng
    /// </summary>
    public void Claim()
    {
        if (Status != RewardStatus.Pending)
            throw new InvalidOperationException($"Cannot claim reward in {Status} status");
            
        if (ExpiresAt.HasValue && DateTime.UtcNow > ExpiresAt.Value)
        {
            Status = RewardStatus.Expired;
            throw new InvalidOperationException("Reward has expired");
        }
        
        Status = RewardStatus.Claimed;
        ClaimedAt = DateTime.UtcNow;
    }
    
    /// <summary>
    /// EN: Mark as expired / VI: Đánh dấu hết hạn
    /// </summary>
    public void Expire()
    {
        if (Status == RewardStatus.Claimed)
            throw new InvalidOperationException("Cannot expire already claimed reward");
            
        Status = RewardStatus.Expired;
    }
    
    /// <summary>
    /// EN: Cancel the reward / VI: Hủy phần thưởng
    /// </summary>
    public void Cancel(string reason)
    {
        if (Status == RewardStatus.Claimed)
            throw new InvalidOperationException("Cannot cancel already claimed reward");
            
        Status = RewardStatus.Cancelled;
    }
}

/// <summary>
/// EN: Reward types / VI: Các loại phần thưởng
/// </summary>
public enum RewardType
{
    /// <summary>EN: Mission completion / VI: Hoàn thành mission</summary>
    MissionComplete = 1,
    
    /// <summary>EN: Daily check-in / VI: Điểm danh hàng ngày</summary>
    CheckInDaily = 2,
    
    /// <summary>EN: Check-in milestone / VI: Mốc điểm danh</summary>
    CheckInMilestone = 3,
    
    /// <summary>EN: Referral bonus / VI: Thưởng giới thiệu</summary>
    ReferralBonus = 4,
    
    /// <summary>EN: Social action / VI: Hành động xã hội</summary>
    SocialAction = 5
}

/// <summary>
/// EN: Reward status / VI: Trạng thái phần thưởng
/// </summary>
public enum RewardStatus
{
    /// <summary>EN: Pending claim / VI: Đang chờ nhận</summary>
    Pending = 1,
    
    /// <summary>EN: Claimed / VI: Đã nhận</summary>
    Claimed = 2,
    
    /// <summary>EN: Expired / VI: Đã hết hạn</summary>
    Expired = 3,
    
    /// <summary>EN: Cancelled / VI: Đã hủy</summary>
    Cancelled = 4
}
