/**
 * InvitationToken Entity
 *
 * Represents an invitation token for user registration.
 *
 * Business Rules:
 * - Tokens expire after 7 days by default
 * - Token can only be used once
 * - Email must be unique per active (non-used) invitation
 */

import { UserRole } from './user.entity';

export interface InvitationTokenProps {
  id: string;
  token: string; // Unique random token (e.g., UUID)
  email: string;
  firstName: string;
  lastName: string;
  role: UserRole;
  organizationId: string;
  invitedById: string; // User ID who created the invitation
  expiresAt: Date;
  usedAt?: Date;
  isUsed: boolean;
  createdAt: Date;
}

export class InvitationToken {
  private readonly props: InvitationTokenProps;

  private constructor(props: InvitationTokenProps) {
    this.props = props;
  }

  /**
   * Factory method to create a new InvitationToken
   */
  static create(
    props: Omit<InvitationTokenProps, 'createdAt' | 'isUsed' | 'usedAt'>
  ): InvitationToken {
    const now = new Date();

    // Validate token
    if (!props.token || props.token.trim().length === 0) {
      throw new Error('Invitation token cannot be empty.');
    }

    // Validate email format
    if (!InvitationToken.isValidEmail(props.email)) {
      throw new Error('Invalid email format.');
    }

    // Validate expiration date
    if (props.expiresAt <= now) {
      throw new Error('Expiration date must be in the future.');
    }

    return new InvitationToken({
      ...props,
      isUsed: false,
      createdAt: now,
    });
  }

  /**
   * Factory method to reconstitute from persistence
   */
  static fromPersistence(props: InvitationTokenProps): InvitationToken {
    return new InvitationToken(props);
  }

  /**
   * Validate email format
   */
  private static isValidEmail(email: string): boolean {
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailPattern.test(email);
  }

  // Getters
  get id(): string {
    return this.props.id;
  }

  get token(): string {
    return this.props.token;
  }

  get email(): string {
    return this.props.email;
  }

  get firstName(): string {
    return this.props.firstName;
  }

  get lastName(): string {
    return this.props.lastName;
  }

  get role(): UserRole {
    return this.props.role;
  }

  get organizationId(): string {
    return this.props.organizationId;
  }

  get invitedById(): string {
    return this.props.invitedById;
  }

  get expiresAt(): Date {
    return this.props.expiresAt;
  }

  get usedAt(): Date | undefined {
    return this.props.usedAt;
  }

  get isUsed(): boolean {
    return this.props.isUsed;
  }

  get createdAt(): Date {
    return this.props.createdAt;
  }

  // Business methods
  isExpired(): boolean {
    return new Date() > this.props.expiresAt;
  }

  isValid(): boolean {
    return !this.props.isUsed && !this.isExpired();
  }

  markAsUsed(): void {
    if (this.props.isUsed) {
      throw new Error('Invitation token has already been used.');
    }

    if (this.isExpired()) {
      throw new Error('Invitation token has expired.');
    }

    this.props.isUsed = true;
    this.props.usedAt = new Date();
  }

  /**
   * Convert to plain object for persistence
   */
  toObject(): InvitationTokenProps {
    return { ...this.props };
  }
}
