import { ChangeDetectorRef, Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ActivatedRoute, Router } from '@angular/router';
import { LootboxService } from '../services/lootbox.service';
import { LootBox, Reward } from 'app/model/LootBox';
import { UserService } from '@service/user.service';
import { User } from 'app/model/User';
import { AuthService } from '@service/auth.service';

@Component({
  selector: 'app-lootbox-opening',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './lootbox-opening.component.html',
  styleUrls: ['./lootbox-opening.component.css'],
})
export default class LootboxOpeningComponent {
  lootbox: LootBox | null = null;
  isLoading = true;
  error = '';
  isOpening = false;
  isOpen = false;
  wonReward: Reward | null = null;
  prizeList: Reward[] = [];
  animationCompleted = false;
  currentUser: User | null = null;
  private winSound: HTMLAudioElement;

  private route = inject(ActivatedRoute);
  private router = inject(Router);
  private lootboxService = inject(LootboxService);
  private userService = inject(UserService);
  private authService = inject(AuthService);
  private cdr = inject(ChangeDetectorRef);

  constructor() {
    this.winSound = new Audio('/sounds/win.mp3');
    this.loadLootbox();
    this.authService.userSubject.subscribe((user) => {
      this.currentUser = user;
      this.cdr.detectChanges();
    });
  }

  private loadLootbox(): void {
    const idParam = this.route.snapshot.paramMap.get('id');
    if (!idParam) {
      this.error = 'Invalid lootbox ID';
      this.isLoading = false;
      return;
    }

    const lootboxId = parseInt(idParam, 10);
    this.lootboxService.getAllLootBoxes().subscribe({
      next: (lootboxes) => {
        this.lootbox = lootboxes.find((box) => box.id === lootboxId) || null;
        this.isLoading = false;
        this.cdr.detectChanges();
      },
      error: () => {
        this.error = 'Failed to load lootbox data';
        this.isLoading = false;
        this.cdr.detectChanges();
      },
    });
  }

  openLootbox(): void {
    if (!this.lootbox || this.isOpening) return;

    // Check if user has enough balance
    if (!this.hasEnoughBalance()) {
      this.error = 'Nicht genug Guthaben, um diese Lootbox zu öffnen.';
      window.scrollTo(0, 0);
      this.cdr.detectChanges();
      setTimeout(() => {
        this.error = '';
        this.cdr.detectChanges();
      }, 5000);
      return;
    }

    this.resetState(true);

    if (this.lootbox.price) {
      this.userService.updateLocalBalance(-this.lootbox.price);
    }

    setTimeout(() => {
      this.lootboxService.purchaseLootBox(this.lootbox!.id).subscribe({
        next: this.handleRewardSuccess.bind(this),
        error: this.handleRewardError.bind(this),
      });
    }, 100);
  }

  private handleRewardSuccess(reward: Reward): void {
    this.wonReward = reward;
    this.generateCasePrizes(reward);
    this.isOpening = false;
    this.isOpen = true;

    this.cdr.detectChanges();
  }

  private handleRewardError(): void {
    if (!this.lootbox) return;

    const rewards = this.lootbox.rewards;
    const fallback = rewards[Math.floor(Math.random() * rewards.length)];

    this.wonReward = fallback;
    this.generateCasePrizes(fallback);
    this.isOpening = false;
    this.isOpen = true;
    this.cdr.detectChanges();
  }

  private resetState(isOpening = false): void {
    this.isOpening = isOpening;
    this.isOpen = false;
    this.wonReward = null;
    this.prizeList = [];
    this.animationCompleted = false;
    this.cdr.detectChanges();
  }

  generateCasePrizes(wonReward: Reward): void {
    if (!this.lootbox) return;

    const prizeCount = 120;
    const winningPosition = Math.floor(prizeCount / 2);
    const possibleRewards = this.lootbox.rewards;
    const items: Reward[] = [];

    for (let i = 0; i < prizeCount; i++) {
      if (i === winningPosition) {
        items.push({ ...wonReward });
      } else {
        items.push(this.getWeightedRandomReward(possibleRewards));
      }
    }

    this.prizeList = items;

    setTimeout(() => {
      this.animationCompleted = true;

      if (this.wonReward) {
        this.winSound.play();
        this.userService.updateLocalBalance(this.wonReward.value);
      }

      this.userService.refreshCurrentUser();
      this.cdr.detectChanges();
    }, 10000);
  }

  getWeightedRandomReward(rewards: Reward[]): Reward {
    const totalProbability = rewards.reduce((sum, reward) => sum + reward.probability, 0);
    const randomValue = Math.random() * totalProbability;
    let cumulativeProbability = 0;

    for (const reward of rewards) {
      cumulativeProbability += reward.probability;
      if (randomValue <= cumulativeProbability) {
        return { ...reward };
      }
    }

    return { ...rewards[0] };
  }

  openAgain(): void {
    this.resetState();
    this.openLootbox();
  }

  getBoxImage(id: number): string {
    return `/images/${id}-box.png`;
  }

  goBack(): void {
    this.router.navigate(['/game/lootboxes']);
  }

  isWonReward(reward: Reward): boolean {
    if (!this.wonReward || !this.prizeList.length) return false;

    const middleIndex = Math.floor(this.prizeList.length / 2);
    return this.prizeList.indexOf(reward) === middleIndex;
  }

  getRewardRarityClass(reward: Reward): string {
    if (!reward) return 'text-common';

    const probability = reward.probability;

    if (probability < 0.01) return 'text-mythic';
    if (probability < 0.05) return 'text-legendary';
    if (probability < 0.1) return 'text-epic';
    if (probability < 0.2) return 'text-rare';
    if (probability < 0.4) return 'text-uncommon';
    return 'text-common';
  }

  getRewardClass(): string {
    if (!this.wonReward || !this.lootbox) return '';
    return this.wonReward.value > (this.lootbox.price || 0) ? 'text-emerald' : 'text-accent-red';
  }

  hasEnoughBalance(): boolean {
    if (!this.currentUser || !this.lootbox) return false;
    return this.currentUser.balance >= this.lootbox.price;
  }
}
