import { Directive, ElementRef, Input, OnChanges, OnDestroy } from '@angular/core';

const OBFUSCATION_CHARS =
  '!@#$%^&*()_+-=[]{}|;:,.<>?/~`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

/**
 * Apply as `[mmObfuscated]="style.obfuscated"` on an element whose textContent is the
 * text to obfuscate. While active, cycles every character (except spaces) through random
 * glyphs, mimicking Minecraft's "magic" formatting. The real text is preserved in an
 * aria-label so it stays accessible to screen readers, and is restored to the DOM when
 * obfuscation is turned off.
 */
@Directive({
  selector: '[mmObfuscated]',
  standalone: true,
})
export class ObfuscatedDirective implements OnChanges, OnDestroy {
  @Input('mmObfuscated') active = false;

  private original: string | null = null;
  private intervalId: ReturnType<typeof setInterval> | undefined;

  constructor(private readonly el: ElementRef<HTMLElement>) {}

  ngOnChanges(): void {
    if (this.original === null) {
      this.original = this.el.nativeElement.textContent ?? '';
      this.el.nativeElement.setAttribute('aria-label', this.original);
    }
    this.sync();
  }

  ngOnDestroy(): void {
    this.stop();
  }

  private sync(): void {
    if (this.active && !this.intervalId) {
      this.start();
    } else if (!this.active && this.intervalId) {
      this.stop();
    }
  }

  private start(): void {
    this.intervalId = setInterval(() => {
      const text = this.original ?? '';
      const scrambled = text
        .split('')
        .map((ch) => (ch === ' ' ? ' ' : OBFUSCATION_CHARS[Math.floor(Math.random() * OBFUSCATION_CHARS.length)]))
        .join('');
      this.el.nativeElement.textContent = scrambled;
    }, 50);
  }

  private stop(): void {
    if (this.intervalId) {
      clearInterval(this.intervalId);
      this.intervalId = undefined;
    }
    if (this.original !== null) {
      this.el.nativeElement.textContent = this.original;
    }
  }
}
