import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Router } from '@angular/router';
import { DealerHandComponent } from './components/dealer-hand/dealer-hand.component';
import { PlayerHandComponent } from './components/player-hand/player-hand.component';
import { GameControlsComponent } from './components/game-controls/game-controls.component';
import { GameInfoComponent } from './components/game-info/game-info.component';
import { BlackjackGame, Card } from '@blackjack/models/blackjack.model';
import { BlackjackService } from '@blackjack/services/blackjack.service';
import { HttpErrorResponse } from '@angular/common/http';
import { GameResultComponent } from '@blackjack/components/game-result/game-result.component';
import { GameState } from '@blackjack/enum/gameState';
import { UserService } from '@service/user.service';
import { timer } from 'rxjs';
import { DebtDialogComponent } from '@shared/components/debt-dialog/debt-dialog.component';
import { AuthService } from '@service/auth.service';
import { AudioService } from '@shared/services/audio.service';

@Component({
  selector: 'app-blackjack',
  standalone: true,
  imports: [
    CommonModule,
    DealerHandComponent,
    PlayerHandComponent,
    GameControlsComponent,
    GameInfoComponent,
    GameResultComponent,
    DebtDialogComponent,
  ],
  templateUrl: './blackjack.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export default class BlackjackComponent implements OnInit {
  private router = inject(Router);
  private userService = inject(UserService);
  private authService = inject(AuthService);
  private blackjackService = inject(BlackjackService);
  private audioService = inject(AudioService);

  dealerCards = signal<Card[]>([]);
  playerCards = signal<Card[]>([]);
  currentBet = signal(0);
  balance = signal(0);
  currentGameId = signal<number | undefined>(undefined);
  gameInProgress = signal(false);
  gameState = signal<GameState>(GameState.IN_PROGRESS);
  showGameResult = signal(false);

  isActionInProgress = signal(false);

  showDebtDialog = signal(false);
  debtAmount = signal(0);

  ngOnInit(): void {
    // Subscribe to user updates for real-time balance changes
    this.authService.userSubject.subscribe((user) => {
      if (user) {
        this.balance.set(user.balance);
      }
    });
  }

  private updateGameState(game: BlackjackGame) {
    console.log('Game state update:', game);
    this.currentGameId.set(game.id);
    this.currentBet.set(game.bet);
    this.gameInProgress.set(game.state === GameState.IN_PROGRESS);
    this.gameState.set(game.state as GameState);

    const isGameOver = game.state !== GameState.IN_PROGRESS;

    this.dealerCards.set(
      game.dealerCards.map((card, index) => ({
        ...card,
        hidden: !isGameOver && index === 1 && game.state === GameState.IN_PROGRESS,
      }))
    );

    this.playerCards.set(
      game.playerCards.map((card) => ({
        ...card,
        hidden: false,
      }))
    );

    if (isGameOver) {
      console.log('Game is over, state:', game.state);
      this.userService.refreshCurrentUser();

      // Get the latest balance before showing the result dialog
      timer(1000).subscribe(() => {
        // Show the result dialog after refreshing user data
        timer(500).subscribe(() => {
          this.showGameResult.set(true);
          if (game.state === GameState.PLAYER_WON || game.state === GameState.PLAYER_BLACKJACK) {
            this.audioService.playWinSound();
          }
          console.log('Game result dialog shown after delay');
        });
      });
    }
  }

  onNewGame(bet: number): void {
    this.isActionInProgress.set(true);
    this.audioService.playBetSound();

    this.blackjackService.startGame(bet).subscribe({
      next: (game) => {
        this.updateGameState(game);
        this.userService.refreshCurrentUser();
        this.isActionInProgress.set(false);
      },
      error: (error) => {
        console.error('Failed to start game:', error);
        this.isActionInProgress.set(false);
      },
    });
  }

  onHit(): void {
    if (!this.currentGameId() || this.isActionInProgress()) return;

    this.isActionInProgress.set(true);
    this.audioService.playBetSound();

    this.blackjackService.hit(this.currentGameId()!).subscribe({
      next: (game) => {
        this.updateGameState(game);
        if (game.state !== 'IN_PROGRESS') {
          this.userService.refreshCurrentUser();
        }
        this.isActionInProgress.set(false);
      },
      error: (error) => {
        console.error('Failed to hit:', error);
        this.handleGameError(error);
        this.isActionInProgress.set(false);
      },
    });
  }

  onStand(): void {
    if (!this.currentGameId() || this.isActionInProgress()) return;

    if (this.gameState() !== GameState.IN_PROGRESS) {
      console.log('Cannot stand: game is not in progress');
      return;
    }

    this.isActionInProgress.set(true);
    this.audioService.playBetSound();

    this.blackjackService.stand(this.currentGameId()!).subscribe({
      next: (game) => {
        this.updateGameState(game);
        this.userService.refreshCurrentUser();
        this.isActionInProgress.set(false);
      },
      error: (error) => {
        console.error('Failed to stand:', error);
        this.handleGameError(error);
        this.isActionInProgress.set(false);
      },
    });
  }

  onDoubleDown(): void {
    if (!this.currentGameId() || this.isActionInProgress()) return;

    if (this.gameState() !== GameState.IN_PROGRESS || this.playerCards().length !== 2) {
      console.log('Cannot double down: game is not in progress or more than 2 cards');
      return;
    }

    this.isActionInProgress.set(true);
    this.audioService.playBetSound();

    this.blackjackService.doubleDown(this.currentGameId()!).subscribe({
      next: (game) => {
        this.updateGameState(game);

        // Wait a bit to ensure the backend has finished processing
        timer(1000).subscribe(() => {
          const user = this.authService.currentUserValue;
          if (user && user.balance < 0) {
            this.debtAmount.set(Math.abs(user.balance));
            this.showDebtDialog.set(true);
          }
        });

        this.isActionInProgress.set(false);
      },
      error: (error) => {
        console.error('Failed to double down:', error);
        this.handleGameError(error);
        this.isActionInProgress.set(false);
      },
    });
  }

  onCloseGameResult(): void {
    console.log('Closing game result dialog');
    this.showGameResult.set(false);
  }

  onCloseDebtDialog(): void {
    this.showDebtDialog.set(false);
  }

  private handleGameError(error: HttpErrorResponse): void {
    if (error instanceof HttpErrorResponse) {
      if (error.status === 400 && error.error?.error === 'Invalid state') {
        this.gameInProgress.set(false);
        this.userService.refreshCurrentUser();
      } else if (error.status === 500) {
        console.log('Server error occurred. The game may have been updated in another session.');
        this.gameInProgress.set(false);
        this.userService.refreshCurrentUser();
        if (this.currentGameId()) {
          this.refreshGameState(this.currentGameId()!);
        }
      }
    }
  }

  private refreshGameState(gameId: number): void {
    this.blackjackService.getGame(gameId).subscribe({
      next: (game) => {
        this.updateGameState(game);
      },
      error: (err) => {
        console.error('Failed to refresh game state:', err);
      },
    });
  }

  leaveGame(): void {
    this.router.navigate(['/home']);
  }
}
