import { NgClass, NgIf, CurrencyPipe, CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import {
  ChangeDetectionStrategy,
  Component,
  ElementRef,
  inject,
  OnInit,
  signal,
  ViewChild,
} from '@angular/core';
import { AnimatedNumberComponent } from '@blackjack/components/animated-number/animated-number.component';
import { catchError, finalize } from 'rxjs/operators';
import { of } from 'rxjs';
import { AuthService } from '@service/auth.service';
import { AudioService } from '@shared/services/audio.service';
import { CoinflipGame, CoinflipRequest } from './models/coinflip.model';

@Component({
  selector: 'app-coinflip',
  standalone: true,
  imports: [AnimatedNumberComponent, CurrencyPipe, FormsModule, CommonModule, NgIf, NgClass],
  templateUrl: './coinflip.component.html',
  styleUrl: './coinflip.component.css',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export default class CoinflipComponent implements OnInit {
  currentBet = signal(10);
  balance = signal(0);
  gameInProgress = signal(false);
  isActionInProgress = signal(false);
  gameResult = signal<CoinflipGame | null>(null);
  betInputValue = signal(10);
  errorMessage = signal('');
  isInvalidBet = signal(false);

  @ViewChild('coinElement') coinElement?: ElementRef;

  audioService = inject(AudioService);
  authService = inject(AuthService);
  private http = inject(HttpClient);

  private coinflipSound?: HTMLAudioElement;

  ngOnInit(): void {
    // Abonniere Benutzerupdates für Echtzeitaktualisierungen des Guthabens
    this.authService.userSubject.subscribe((user) => {
      if (user) {
        this.balance.set(user.balance);
      }
    });

    // Initialisiere Münzwurf-Sound
    this.coinflipSound = new Audio('/sounds/coinflip.mp3');
  }

  setBetAmount(percentage: number) {
    const newBet = Math.floor(this.balance() * percentage);
    this.betInputValue.set(newBet > 0 ? newBet : 1);
    this.currentBet.set(this.betInputValue());
  }

  updateBet(event: Event) {
    const inputElement = event.target as HTMLInputElement;
    let value = Number(inputElement.value);

    // Setze ungültigen Einsatz-Status zurück
    this.isInvalidBet.set(false);

    // Erzwinge Mindesteinsatz von 1
    if (value <= 0) {
      value = 1;
    }

    // Begrenze Einsatz auf verfügbares Guthaben und zeige Feedback
    if (value > this.balance()) {
      value = this.balance();
      // Visuelles Feedback anzeigen
      this.isInvalidBet.set(true);
      // Zeige den Fehler kurz an
      setTimeout(() => this.isInvalidBet.set(false), 800);
      // Aktualisiere das Eingabefeld direkt, um dem Benutzer den maximalen Wert anzuzeigen
      inputElement.value = String(value);
    }

    // Aktualisiere Signale
    this.betInputValue.set(value);
    this.currentBet.set(value);
  }

  betHeads() {
    this.placeBet('HEAD');
  }

  betTails() {
    this.placeBet('TAILS');
  }

  private placeBet(side: 'HEAD' | 'TAILS') {
    if (this.gameInProgress() || this.isActionInProgress()) return;

    // Setze vorheriges Ergebnis zurück
    this.gameResult.set(null);
    this.errorMessage.set('');

    // Setze Spielstatus
    this.gameInProgress.set(true);
    this.isActionInProgress.set(true);

    // Spiele Einsatz-Sound
    this.audioService.playBetSound();

    // Erstelle Einsatz-Anfrage
    const request: CoinflipRequest = {
      betAmount: this.currentBet(),
      coinSide: side,
    };

    // API aufrufen
    this.http
      .post<CoinflipGame>('/backend/coinflip', request)
      .pipe(
        catchError((error) => {
          console.error('Fehler beim Spielen von Coinflip:', error);

          if (error.status === 400 && error.error.message.includes('insufficient')) {
            this.errorMessage.set('Unzureichendes Guthaben');
          } else {
            this.errorMessage.set('Ein Fehler ist aufgetreten. Bitte versuche es erneut.');
          }

          this.gameInProgress.set(false);
          return of(null);
        }),
        finalize(() => {
          this.isActionInProgress.set(false);
        })
      )
      .subscribe((result) => {
        if (!result) return;

        console.log('API-Antwort:', result);

        // Behebe mögliche Inkonsistenzen bei der Eigenschaftenbenennung vom Backend
        const fixedResult: CoinflipGame = {
          isWin: result.isWin ?? result.win,
          payout: result.payout,
          coinSide: result.coinSide,
        };

        console.log('Korrigiertes Ergebnis:', fixedResult);

        // Spiele Münzwurf-Animation und -Sound
        this.playCoinFlipAnimation(fixedResult.coinSide);

        // Setze Ergebnis nach Abschluss der Animation
        setTimeout(() => {
          this.gameResult.set(fixedResult);

          // Aktualisiere Guthaben mit neuem Wert vom Auth-Service
          this.authService.loadCurrentUser();

          // Spiele Gewinn-Sound, wenn der Spieler gewonnen hat
          if (fixedResult.isWin) {
            this.audioService.playWinSound();
          }

          // Setze Spielstatus nach Anzeigen des Ergebnisses zurück
          setTimeout(() => {
            this.gameInProgress.set(false);
          }, 1500);
        }, 1100); // Kurz nach Ende der Animation
      });
  }

  private playCoinFlipAnimation(result: 'HEAD' | 'TAILS') {
    if (!this.coinElement) return;

    const coinEl = this.coinElement.nativeElement;

    // Setze bestehende Animationen zurück
    coinEl.classList.remove('animate-to-heads', 'animate-to-tails');

    // Setze alle Inline-Styles von vorherigen Animationen zurück
    coinEl.style.transform = '';

    // Erzwinge Reflow, um Animation neu zu starten
    void coinEl.offsetWidth;

    // Spiele Münzwurf-Sound
    if (this.coinflipSound) {
      this.coinflipSound.currentTime = 0;
      this.coinflipSound
        .play()
        .catch((err) => console.error('Fehler beim Abspielen des Sounds:', err));
    }

    // Füge passende Animationsklasse basierend auf dem Ergebnis hinzu
    if (result === 'HEAD') {
      coinEl.classList.add('animate-to-heads');
    } else {
      coinEl.classList.add('animate-to-tails');
    }

    console.log(`Animation angewendet für Ergebnis: ${result}`);
  }

  /**
   * Validiert Eingabe während der Benutzer tippt, um ungültige Werte zu verhindern
   */
  validateBetInput(event: KeyboardEvent) {
    // Erlaube Navigationstasten (Pfeile, Entf, Rücktaste, Tab)
    const navigationKeys = ['ArrowLeft', 'ArrowRight', 'Delete', 'Backspace', 'Tab'];
    if (navigationKeys.includes(event.key)) {
      return;
    }

    // Erlaube nur Zahlen
    if (!/^\d$/.test(event.key)) {
      event.preventDefault();
      return;
    }

    // Ermittle den Wert, der nach dem Tastendruck entstehen würde
    const input = event.target as HTMLInputElement;
    const currentValue = input.value;
    const cursorPosition = input.selectionStart || 0;
    const newValue =
      currentValue.substring(0, cursorPosition) +
      event.key +
      currentValue.substring(input.selectionEnd || cursorPosition);
    const numValue = Number(newValue);

    // Verhindere Werte, die größer als das Guthaben sind
    if (numValue > this.balance()) {
      event.preventDefault();
    }
  }

  // Der Paste-Handler wurde der Einfachheit halber entfernt, da die updateBet-Methode
  // jeden Wert behandelt, der in das Eingabefeld gelangt

  getResultClass() {
    if (!this.gameResult()) return '';
    const result = this.gameResult();
    const isWinner = result?.isWin || result?.win;
    return isWinner ? 'text-emerald-500' : 'text-accent-red';
  }
}
