/**
 * Domain Entity: UserAchievement
 *
 * Represents an achievement earned by a specific user.
 */

import type { IEntity } from '@core/shared/domain';

export interface UserAchievementProps {
  id: string;
  userId: string;
  achievementId: string;
  earnedAt: Date;
  notifiedAt?: Date;
  progress?: number; // For partial progress tracking (0-100)
}

export class UserAchievement implements IEntity<string> {
  readonly id: string;
  readonly userId: string;
  readonly achievementId: string;
  readonly earnedAt: Date;
  readonly notifiedAt: Date | undefined;
  readonly progress: number;

  private constructor(props: UserAchievementProps) {
    this.id = props.id;
    this.userId = props.userId;
    this.achievementId = props.achievementId;
    this.earnedAt = props.earnedAt;
    this.notifiedAt = props.notifiedAt;
    this.progress = props.progress ?? 100;
  }

  static create(props: UserAchievementProps): UserAchievement {
    if (!props.id || props.id.trim().length === 0) {
      throw new Error('UserAchievement ID is required');
    }

    if (!props.userId || props.userId.trim().length === 0) {
      throw new Error('UserAchievement userId is required');
    }

    if (!props.achievementId || props.achievementId.trim().length === 0) {
      throw new Error('UserAchievement achievementId is required');
    }

    return new UserAchievement(props);
  }

  /**
   * Mark achievement as notified to user
   */
  markNotified(): UserAchievement {
    return new UserAchievement({
      id: this.id,
      userId: this.userId,
      achievementId: this.achievementId,
      earnedAt: this.earnedAt,
      notifiedAt: new Date(),
      progress: this.progress,
    });
  }

  /**
   * Update progress towards achievement
   */
  updateProgress(progress: number): UserAchievement {
    const clampedProgress = Math.max(0, Math.min(100, progress));
    return new UserAchievement({
      id: this.id,
      userId: this.userId,
      achievementId: this.achievementId,
      earnedAt: this.earnedAt,
      ...(this.notifiedAt ? { notifiedAt: this.notifiedAt } : {}),
      progress: clampedProgress,
    });
  }

  /**
   * Check if achievement is fully earned
   */
  isComplete(): boolean {
    return this.progress >= 100;
  }

  /**
   * Check if user has been notified
   */
  isNotified(): boolean {
    return this.notifiedAt !== undefined;
  }
}